blob: 00debb6e8c4723593e2ff9d1e9a57c2b989f4672 [file] [log] [blame]
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +08001/* MTP layer3 main handling code */
2/*
3 * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
4 * (C) 2010 by On-Waves
5 * All Rights Reserved
6 *
Holger Hans Peter Freytherde56c222011-01-16 17:45:14 +01007 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080010 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Holger Hans Peter Freytherde56c222011-01-16 17:45:14 +010015 * GNU Affero General Public License for more details.
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080016 *
Holger Hans Peter Freytherde56c222011-01-16 17:45:14 +010017 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080019 *
20 */
21#include <mtp_data.h>
22#include <mtp_level3.h>
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +010023#include <bsc_data.h>
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080024#include <cellmgr_debug.h>
Holger Hans Peter Freyther433ea2f2010-12-10 07:34:01 +010025#include <isup_types.h>
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +010026#include <counter.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080027
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080028#include <osmocore/talloc.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080029
Holger Hans Peter Freythercf381e22010-08-04 18:39:26 +080030#include <osmocom/sccp/sccp.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080031
32#include <arpa/inet.h>
33
34#include <string.h>
35
36static void *tall_mtp_ctx = NULL;
37
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +010038static int mtp_int_submit(struct mtp_link_set *link, int pc, int sls, int type, const uint8_t *data, unsigned int length);
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +010039
Holger Hans Peter Freyther9543f4a2011-01-24 20:49:58 +010040void mtp_link_submit(struct mtp_link *link, struct msgb *msg)
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +010041{
Holger Hans Peter Freyther4c1eb0e2011-01-22 15:52:07 +010042 rate_ctr_inc(&link->ctrg->ctr[MTP_LNK_OUT]);
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +010043 rate_ctr_inc(&link->set->ctrg->ctr[MTP_LSET_TOTA_OUT_MSG]);
44 link->write(link, msg);
45}
46
47
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +010048struct msgb *mtp_msg_alloc(struct mtp_link_set *link)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080049{
50 struct mtp_level_3_hdr *hdr;
51 struct msgb *msg = msgb_alloc_headroom(4096, 128, "mtp-msg");
52 if (!msg) {
53 LOGP(DINP, LOGL_ERROR, "Failed to allocate mtp msg\n");
54 return NULL;
55 }
56
57 msg->l2h = msgb_put(msg, sizeof(*hdr));
58 hdr = (struct mtp_level_3_hdr *) msg->l2h;
59 hdr->addr = MTP_ADDR(0x0, link->dpc, link->opc);
Holger Hans Peter Freyther4e3e28e2010-11-26 21:05:39 +010060 hdr->ni = link->ni;
Holger Hans Peter Freythere976df12010-11-26 21:07:11 +010061 hdr->spare = link->spare;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080062 return msg;
63}
64
Holger Hans Peter Freyther050577a2011-01-20 19:28:15 +010065static struct msgb *mtp_create_slta(struct mtp_link_set *link, int sls,
66 struct mtp_level_3_mng *in_mng, int l3_len)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080067{
68 struct mtp_level_3_hdr *hdr;
69 struct mtp_level_3_mng *mng;
70 struct msgb *out = mtp_msg_alloc(link);
71
72 if (!out)
73 return NULL;
74
75 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080076 hdr->ser_ind = MTP_SI_MNT_REG_MSG;
Holger Hans Peter Freyther050577a2011-01-20 19:28:15 +010077 hdr->addr = MTP_ADDR(sls, link->dpc, link->opc);
78
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080079 mng = (struct mtp_level_3_mng *) msgb_put(out, sizeof(*mng));
80 mng->cmn.h0 = MTP_TST_MSG_GRP;
81 mng->cmn.h1 = MTP_TST_MSG_SLTA;
82 mng->length = l3_len - 2;
83 msgb_put(out, mng->length);
84 memcpy(mng->data, in_mng->data, mng->length);
85
86 return out;
87}
88
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +010089
Holger Hans Peter Freytherfd5d8d22011-01-25 13:35:10 +010090static struct msgb *mtp_base_alloc(struct mtp_link *link, int msg, int apoc)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080091{
92 struct mtp_level_3_hdr *hdr;
93 struct mtp_level_3_prohib *prb;
Holger Hans Peter Freytherfd5d8d22011-01-25 13:35:10 +010094 struct msgb *out = mtp_msg_alloc(link->set);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080095
96 if (!out)
97 return NULL;
98
99 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800100 hdr->ser_ind = MTP_SI_MNT_SNM_MSG;
Holger Hans Peter Freytherfd5d8d22011-01-25 13:35:10 +0100101 hdr->addr = MTP_ADDR(link->first_sls, link->set->dpc, link->set->opc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800102 prb = (struct mtp_level_3_prohib *) msgb_put(out, sizeof(*prb));
103 prb->cmn.h0 = MTP_PROHIBIT_MSG_GRP;
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100104 prb->cmn.h1 = msg;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800105 prb->apoc = MTP_MAKE_APOC(apoc);
106 return out;
107}
108
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100109static struct msgb *mtp_tfp_alloc(struct mtp_link *link, int apoc)
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100110{
Holger Hans Peter Freytherfd5d8d22011-01-25 13:35:10 +0100111 return mtp_base_alloc(link, MTP_PROHIBIT_MSG_SIG, apoc);
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100112}
113
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100114static struct msgb *mtp_tfa_alloc(struct mtp_link *link, int apoc)
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100115{
Holger Hans Peter Freytherfd5d8d22011-01-25 13:35:10 +0100116 return mtp_base_alloc(link, MTP_PROHIBIT_MSG_TFA, apoc);
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100117}
118
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100119static struct msgb *mtp_tra_alloc(struct mtp_link *link, int opc)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800120{
121 struct mtp_level_3_hdr *hdr;
122 struct mtp_level_3_cmn *cmn;
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100123 struct msgb *out = mtp_msg_alloc(link->set);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800124
125 if (!out)
126 return NULL;
127
128 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800129 hdr->ser_ind = MTP_SI_MNT_SNM_MSG;
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100130 hdr->addr = MTP_ADDR(0x0, link->set->dpc, opc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800131 cmn = (struct mtp_level_3_cmn *) msgb_put(out, sizeof(*cmn));
132 cmn->h0 = MTP_TRF_RESTR_MSG_GRP;
133 cmn->h1 = MTP_RESTR_MSG_ALLWED;
134 return out;
135}
136
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100137static struct msgb *mtp_sccp_alloc_scmg(struct mtp_link_set *link,
Holger Hans Peter Freyther101cd0b2011-01-19 10:51:44 +0100138 int type, int assn, int apoc, int sls)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800139{
140 struct sccp_data_unitdata *udt;
141 struct sccp_con_ctrl_prt_mgt *prt;
142 struct mtp_level_3_hdr *hdr;
Holger Hans Peter Freyther5aa17012010-07-31 04:37:26 +0800143 uint8_t *data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800144
145
146 struct msgb *out = mtp_msg_alloc(link);
147
148 if (!out)
149 return NULL;
150
151 hdr = (struct mtp_level_3_hdr *) out->l2h;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800152 hdr->ser_ind = MTP_SI_MNT_SCCP;
153
154 /* this appears to be round robin or such.. */
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100155 hdr->addr = MTP_ADDR(sls % 16, link->dpc, link->sccp_opc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800156
157 /* generate the UDT message... libsccp does not offer formating yet */
158 udt = (struct sccp_data_unitdata *) msgb_put(out, sizeof(*udt));
159 udt->type = SCCP_MSG_TYPE_UDT;
160 udt->proto_class = SCCP_PROTOCOL_CLASS_0;
161 udt->variable_called = 3;
162 udt->variable_calling = 5;
163 udt->variable_data = 7;
164
165 /* put the called and calling address. It is LV */
166 data = msgb_put(out, 2 + 1);
167 data[0] = 2;
168 data[1] = 0x42;
169 data[2] = 0x1;
170
171 data = msgb_put(out, 2 + 1);
172 data[0] = 2;
173 data[1] = 0x42;
174 data[2] = 0x1;
175
176 data = msgb_put(out, 1);
177 data[0] = sizeof(*prt);
178
179 prt = (struct sccp_con_ctrl_prt_mgt *) msgb_put(out, sizeof(*prt));
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100180 prt->sst = type;
181 prt->assn = assn;
Holger Hans Peter Freyther101cd0b2011-01-19 10:51:44 +0100182 prt->apoc = apoc;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800183 prt->mul_ind = 0;
184
185 return out;
186}
187
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100188void mtp_link_set_init(void)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800189{
190 tall_mtp_ctx = talloc_named_const(NULL, 1, "mtp-link");
191}
192
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100193struct mtp_link_set *mtp_link_set_alloc(void)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800194{
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100195 static int linkset_no = 0;
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100196 struct mtp_link_set *link;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800197
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100198 link = talloc_zero(tall_mtp_ctx, struct mtp_link_set);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800199 if (!link)
200 return NULL;
201
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100202 link->ctrg = rate_ctr_group_alloc(link,
203 mtp_link_set_rate_ctr_desc(),
204 linkset_no++);
205 if (!link->ctrg) {
206 LOGP(DINP, LOGL_ERROR, "Failed to allocate counter.\n");
207 return NULL;
208 }
209
210
Holger Hans Peter Freyther4e3e28e2010-11-26 21:05:39 +0100211 link->ni = MTP_NI_NATION_NET;
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100212 INIT_LLIST_HEAD(&link->links);
213
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800214 return link;
215}
216
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100217void mtp_link_set_stop(struct mtp_link_set *link)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800218{
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100219 struct mtp_link *lnk;
220 llist_for_each_entry(lnk, &link->links, entry)
221 mtp_link_stop_link_test(lnk);
222
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800223 link->sccp_up = 0;
224 link->running = 0;
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100225 link->linkset_up = 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800226}
227
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100228void mtp_link_set_reset(struct mtp_link_set *link)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800229{
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100230 struct mtp_link *lnk;
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100231 mtp_link_set_stop(link);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800232 link->running = 1;
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100233
234 llist_for_each_entry(lnk, &link->links, entry)
235 mtp_link_start_link_test(lnk);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800236}
237
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100238static int send_tfp(struct mtp_link *link, int apoc)
Holger Hans Peter Freyther27c5e232011-01-18 18:52:34 +0100239{
240 struct msgb *msg;
241 msg = mtp_tfp_alloc(link, apoc);
242 if (!msg)
243 return -1;
244
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100245 mtp_link_submit(link, msg);
Holger Hans Peter Freyther27c5e232011-01-18 18:52:34 +0100246 return 0;
247}
248
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100249static int send_tra(struct mtp_link *link, int opc)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800250{
251 struct msgb *msg;
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100252 msg = mtp_tra_alloc(link, opc);
253 if (!msg)
254 return -1;
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100255 mtp_link_submit(link, msg);
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100256 return 0;
257}
258
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100259static int send_tfa(struct mtp_link *link, int opc)
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100260{
261 struct msgb *msg;
262 msg = mtp_tfa_alloc(link, opc);
263 if (!msg)
264 return -1;
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100265 mtp_link_submit(link, msg);
Holger Hans Peter Freythercfbe80f2011-01-18 20:35:11 +0100266 return 0;
267}
268
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100269static int linkset_up(struct mtp_link *link)
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100270{
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100271 struct mtp_link_set *set = link->set;
272
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100273 /* the link set is already up */
274 if (set->linkset_up)
275 return 0;
276
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100277 if (send_tfp(link, 0) != 0)
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100278 return -1;
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100279 if (send_tfp(link, set->opc) != 0)
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100280 return -1;
281 if (set->sccp_opc != set->opc &&
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100282 send_tfp(link, set->sccp_opc) != 0)
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100283 return -1;
284 if (set->isup_opc != set->opc &&
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100285 send_tfp(link, set->isup_opc) != 0)
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100286 return -1;
287
288 /* Send the TRA for all PCs */
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100289 if (send_tra(link, set->opc) != 0)
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100290 return -1;
291 if (set->sccp_opc != set->opc &&
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100292 send_tfa(link, set->sccp_opc) != 0)
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100293 return -1;
294 if (set->isup_opc != set->opc &&
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100295 send_tfa(link, set->isup_opc) != 0)
Holger Hans Peter Freyther606eae82011-01-20 14:23:10 +0100296 return -1;
297
298 set->linkset_up = 1;
299 LOGP(DINP, LOGL_NOTICE,
300 "The linkset %p is considered running.\n", set);
301 return 0;
302}
303
Holger Hans Peter Freytheradf76922011-01-18 19:01:43 +0100304static int mtp_link_sign_msg(struct mtp_link_set *link, struct mtp_level_3_hdr *hdr, int l3_len)
305{
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800306 struct mtp_level_3_cmn *cmn;
Holger Hans Peter Freytherae741812010-12-08 11:28:12 +0100307 uint16_t *apc;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800308
Holger Hans Peter Freyther4e3e28e2010-11-26 21:05:39 +0100309 if (hdr->ni != link->ni || l3_len < 1) {
Holger Hans Peter Freytherdedb7ce2010-10-08 17:49:24 +0800310 LOGP(DINP, LOGL_ERROR, "Unhandled data (ni: %d len: %d)\n",
311 hdr->ni, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800312 return -1;
313 }
314
315 cmn = (struct mtp_level_3_cmn *) &hdr->data[0];
316 LOGP(DINP, LOGL_DEBUG, "reg msg: h0: 0x%x h1: 0x%x\n",
317 cmn->h0, cmn->h1);
318
319 switch (cmn->h0) {
320 case MTP_TRF_RESTR_MSG_GRP:
321 switch (cmn->h1) {
322 case MTP_RESTR_MSG_ALLWED:
Holger Hans Peter Freytherff9cd6f2010-12-31 21:47:14 +0100323 LOGP(DINP, LOGL_INFO, "Received Restart Allowed. SST could be next: %p\n", link);
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100324 link->sccp_up = 1;
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100325 LOGP(DINP, LOGL_INFO, "SCCP traffic allowed. %p\n", link);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800326 return 0;
327 break;
328 }
329 break;
Holger Hans Peter Freytherae741812010-12-08 11:28:12 +0100330 case MTP_PROHIBIT_MSG_GRP:
331 switch (cmn->h1) {
332 case MTP_PROHIBIT_MSG_SIG:
333 if (l3_len < 3) {
334 LOGP(DINP, LOGL_ERROR, "TFP is too short.\n");
335 return -1;
336 }
337
338 apc = (uint16_t *) &hdr->data[1];
339 LOGP(DINP, LOGL_INFO,
340 "TFP for the affected point code: %d\n", *apc);
341 return 0;
342 break;
343 }
344 break;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800345 }
346
Holger Hans Peter Freyther1291ce52010-12-08 11:10:34 +0100347 LOGP(DINP, LOGL_ERROR, "Unknown message:%d/%d %s\n", cmn->h0, cmn->h1, hexdump(&hdr->data[0], l3_len));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800348 return -1;
349}
350
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100351static 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 +0800352{
353 struct msgb *out;
354 struct mtp_level_3_mng *mng;
355
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100356 if (hdr->ni != link->set->ni || l3_len < 1) {
Holger Hans Peter Freytherdedb7ce2010-10-08 17:49:24 +0800357 LOGP(DINP, LOGL_ERROR, "Unhandled data (ni: %d len: %d)\n",
358 hdr->ni, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800359 return -1;
360 }
361
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100362 if (MTP_ADDR_DPC(hdr->addr) != link->set->opc) {
Holger Hans Peter Freyther157de2a2011-01-20 13:05:54 +0100363 LOGP(DINP, LOGL_ERROR, "MSG for 0x%x not handled by 0x%x\n",
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100364 MTP_ADDR_DPC(hdr->addr), link->set->opc);
Holger Hans Peter Freyther157de2a2011-01-20 13:05:54 +0100365 return -1;
366 }
367
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800368 mng = (struct mtp_level_3_mng *) &hdr->data[0];
369 LOGP(DINP, LOGL_DEBUG, "reg msg: h0: 0x%x h1: 0x%x\n",
370 mng->cmn.h0, mng->cmn.h1);
371
372 switch (mng->cmn.h0) {
373 case MTP_TST_MSG_GRP:
374 switch (mng->cmn.h1) {
375 case MTP_TST_MSG_SLTM:
376 /* simply respond to the request... */
Holger Hans Peter Freyther050577a2011-01-20 19:28:15 +0100377 out = mtp_create_slta(link->set,
378 MTP_LINK_SLS(hdr->addr),
379 mng, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800380 if (!out)
381 return -1;
Holger Hans Peter Freyther9543f4a2011-01-24 20:49:58 +0100382 mtp_link_submit(link, out);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800383 return 0;
384 break;
385 case MTP_TST_MSG_SLTA:
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100386 /* If this link is proven set it up */
387 if (mtp_link_slta(link, l3_len, mng) == 0)
Holger Hans Peter Freyther7d336a52011-01-25 13:29:56 +0100388 linkset_up(link);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800389 break;
390 }
391 break;
392 }
393
394 return -1;
395}
396
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100397static 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 +0800398{
399 struct msgb *out;
400 struct sccp_con_ctrl_prt_mgt *prt;
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100401 struct sccp_parse_result sccp;
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100402 int type;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800403
404 msg->l2h = &hdr->data[0];
405 if (msgb_l2len(msg) != l3_len) {
406 LOGP(DINP, LOGL_ERROR, "Size is wrong after playing with the l2h header.\n");
407 return -1;
408 }
409
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100410 if (!link->sccp_up) {
411 LOGP(DINP, LOGL_ERROR, "SCCP traffic is not allowed.\n");
412 return -1;
413 }
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800414
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100415 memset(&sccp, 0, sizeof(sccp));
416 if (sccp_parse_header(msg, &sccp) != 0) {
417 LOGP(DINP, LOGL_ERROR, "Failed to parsed SCCP header.\n");
418 return -1;
419 }
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800420
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100421 /* check if it is a SST */
422 if (sccp_determine_msg_type(msg) == SCCP_MSG_TYPE_UDT
423 && msg->l3h[0] == SCCP_SST) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800424 if (msgb_l3len(msg) != 5) {
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100425 LOGP(DINP, LOGL_ERROR,
426 "SCCP UDT msg of unexpected size: %u\n",
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800427 msgb_l3len(msg));
428 return -1;
429 }
430
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800431 prt = (struct sccp_con_ctrl_prt_mgt *) &msg->l3h[0];
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100432 if (prt->apoc != MTP_MAKE_APOC(link->sccp_opc)) {
Holger Hans Peter Freyther09459612010-12-31 16:53:40 +0100433 LOGP(DINP, LOGL_ERROR, "Unknown APOC: %u/%u\n",
434 ntohs(prt->apoc), prt->apoc);
435 type = SCCP_SSP;
436 } else if (prt->assn != 1 && prt->assn != 254 &&
437 prt->assn != 7 && prt->assn != 8 && prt->assn != 146) {
438 LOGP(DINP, LOGL_ERROR, "Unknown affected SSN assn: %u\n",
439 prt->assn);
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100440 type = SCCP_SSP;
441 } else {
442 type = SCCP_SSA;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800443 }
444
Holger Hans Peter Freyther101cd0b2011-01-19 10:51:44 +0100445 out = mtp_sccp_alloc_scmg(link, type, prt->assn, prt->apoc,
Holger Hans Peter Freyther80ab4c62010-12-31 13:40:19 +0100446 MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800447 if (!out)
448 return -1;
449
Holger Hans Peter Freyther9543f4a2011-01-24 20:49:58 +0100450 mtp_link_submit(link->slc[MTP_LINK_SLS(hdr->addr)], out);
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100451 return 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800452 }
Holger Hans Peter Freytherd10a3c12010-12-10 12:27:00 +0100453
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100454 rate_ctr_inc(&link->ctrg->ctr[MTP_LSET_SCCP_IN_MSG]);
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100455 mtp_link_set_forward_sccp(link, msg, MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800456 return 0;
457}
458
Holger Hans Peter Freytherbee2ed12011-01-18 13:29:42 +0100459int mtp_link_set_data(struct mtp_link *link, struct msgb *msg)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800460{
461 int rc = -1;
462 struct mtp_level_3_hdr *hdr;
463 int l3_len;
464
465 if (!msg->l2h || msgb_l2len(msg) < sizeof(*hdr))
466 return -1;
467
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100468 if (!link->set->running) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800469 LOGP(DINP, LOGL_ERROR, "Link is not running. Call mtp_link_reset first: %p\n", link);
470 return -1;
471 }
472
473 hdr = (struct mtp_level_3_hdr *) msg->l2h;
474 l3_len = msgb_l2len(msg) - sizeof(*hdr);
475
Holger Hans Peter Freyther326a1f72011-01-24 20:52:30 +0100476 rate_ctr_inc(&link->ctrg->ctr[MTP_LNK_IN]);
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100477 rate_ctr_inc(&link->set->ctrg->ctr[MTP_LSET_TOTA_IN_MSG]);
478
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800479 switch (hdr->ser_ind) {
480 case MTP_SI_MNT_SNM_MSG:
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100481 rc = mtp_link_sign_msg(link->set, hdr, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800482 break;
483 case MTP_SI_MNT_REG_MSG:
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100484 rc = mtp_link_regular_msg(link, hdr, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800485 break;
486 case MTP_SI_MNT_SCCP:
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100487 rc = mtp_link_sccp_data(link->set, hdr, msg, l3_len);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800488 break;
Holger Hans Peter Freyther3a80cb22010-12-08 11:12:46 +0100489 case MTP_SI_MNT_ISUP:
Holger Hans Peter Freyther433ea2f2010-12-10 07:34:01 +0100490 msg->l3h = &hdr->data[0];
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100491 rate_ctr_inc(&link->set->ctrg->ctr[MTP_LSET_IUSP_IN_MSG]);
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100492 rc = mtp_link_set_isup(link->set, msg, MTP_LINK_SLS(hdr->addr));
Holger Hans Peter Freyther3a80cb22010-12-08 11:12:46 +0100493 break;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800494 default:
495 fprintf(stderr, "Unhandled: %u\n", hdr->ser_ind);
496 break;
497 }
498
499 return rc;
500}
501
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100502int 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 +0800503{
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800504
505 if (!link->sccp_up) {
506 LOGP(DINP, LOGL_ERROR, "SCCP msg after TRA and before SSA. Dropping it.\n");
507 return -1;
508 }
509
Holger Hans Peter Freyther346e1c42011-01-02 18:11:37 +0100510 if (sls == -1) {
511 sls = link->last_sls;
512 link->last_sls = (link->last_sls + 1) % 16;
513 }
514
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100515 rate_ctr_inc(&link->ctrg->ctr[MTP_LSET_SCCP_OUT_MSG]);
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100516 return mtp_int_submit(link, link->sccp_opc, sls, MTP_SI_MNT_SCCP, data, length);
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100517}
518
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100519int mtp_link_set_submit_isup_data(struct mtp_link_set *link, int sls,
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100520 const uint8_t *data, unsigned int length)
521{
Holger Hans Peter Freytherc5d897e2011-01-21 20:54:55 +0100522 rate_ctr_inc(&link->ctrg->ctr[MTP_LSET_ISUP_OUT_MSG]);
Holger Hans Peter Freytherd8a73e22011-01-17 22:37:11 +0100523 return mtp_int_submit(link, link->isup_opc, sls, MTP_SI_MNT_ISUP, data, length);
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100524}
525
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +0100526static int mtp_int_submit(struct mtp_link_set *link, int pc, int sls, int type,
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100527 const uint8_t *data, unsigned int length)
528{
529 uint8_t *put_ptr;
530 struct mtp_level_3_hdr *hdr;
531 struct msgb *msg;
532
Holger Hans Peter Freyther92affda2011-01-17 20:12:32 +0100533 if (!link->slc[sls % 16])
534 return -1;
535
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800536 msg = mtp_msg_alloc(link);
537 if (!msg)
538 return -1;
539
540 hdr = (struct mtp_level_3_hdr *) msg->l2h;
Holger Hans Peter Freyther3aad7762010-12-10 12:18:57 +0100541 hdr->ser_ind = type;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800542
Holger Hans Peter Freyther7a725562011-01-01 13:34:58 +0100543 hdr->addr = MTP_ADDR(sls % 16, link->dpc, pc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800544
545 /* copy the raw sccp data */
546 put_ptr = msgb_put(msg, length);
547 memcpy(put_ptr, data, length);
548
Holger Hans Peter Freyther9543f4a2011-01-24 20:49:58 +0100549 mtp_link_submit(link->slc[sls % 16], msg);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800550 return 0;
551}
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100552
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100553static struct mtp_link *find_next_link(struct mtp_link_set *set,
554 struct mtp_link *data)
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100555{
556 int found = 0;
Holger Hans Peter Freyther0e2f9112011-01-17 11:54:39 +0100557 struct mtp_link *next;
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100558
559 if (llist_empty(&set->links))
560 return NULL;
561
562 if (data == NULL)
563 found = 1;
564
565 /* try to find the next one */
566 llist_for_each_entry(next, &set->links, entry) {
567 if (found && next->available)
568 return next;
569 if (next == data)
570 found = 1;
571 }
572
573 /* try to find any one */
574 llist_for_each_entry(next, &set->links, entry)
575 if (next->available)
576 return next;
577
578 return NULL;
579}
580
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100581void mtp_link_set_init_slc(struct mtp_link_set *set)
582{
Holger Hans Peter Freyther1ec2a742011-01-25 13:24:06 +0100583 struct mtp_link *link = NULL, *tmp;
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100584 int i;
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100585
Holger Hans Peter Freyther1ec2a742011-01-25 13:24:06 +0100586 llist_for_each_entry(tmp, &set->links, entry)
587 tmp->first_sls = 100;
588
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100589
590 for (i = 0; i < ARRAY_SIZE(set->slc); ++i) {
591 link = find_next_link(set, link);
592 set->slc[i] = link;
Holger Hans Peter Freyther1ec2a742011-01-25 13:24:06 +0100593
594 if (link && i < link->first_sls)
595 link->first_sls = i;
Holger Hans Peter Freytherd91f9402011-01-16 11:56:05 +0100596 }
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100597}
598
Holger Hans Peter Freyther4c1eb0e2011-01-22 15:52:07 +0100599int mtp_link_set_add_link(struct mtp_link_set *set, struct mtp_link *lnk)
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100600{
Holger Hans Peter Freyther2d845fc2011-01-20 15:42:13 +0100601 lnk->set = set;
Holger Hans Peter Freyther1cc24562011-01-20 18:26:18 +0100602 lnk->link_no = set->nr_links++;
Holger Hans Peter Freyther4c1eb0e2011-01-22 15:52:07 +0100603 if (mtp_link_init(lnk) != 0)
604 return -1;
Holger Hans Peter Freythera8ce0612011-01-20 16:30:24 +0100605
606 llist_add_tail(&lnk->entry, &set->links);
Holger Hans Peter Freytherfe72c162011-01-04 13:21:52 +0100607 mtp_link_set_init_slc(set);
Holger Hans Peter Freyther4c1eb0e2011-01-22 15:52:07 +0100608 return 0;
Holger Hans Peter Freyther069e6352011-01-04 13:01:23 +0100609}