blob: 683a23a8869c5108455a2b39a994a6635f49ec68 [file] [log] [blame]
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +01001/* Run M2UA over SCTP here */
2/* (C) 2011 by Holger Hans Peter Freyther <zecke@selfish.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Affero General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Affero General Public License for more details.
13 *
14 * You should have received a copy of the GNU Affero General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include <sctp_m2ua.h>
19#include <bsc_data.h>
20#include <cellmgr_debug.h>
Holger Hans Peter Freyther4c1eb0e2011-01-22 15:52:07 +010021#include <counter.h>
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +010022#include <mtp_data.h>
Holger Hans Peter Freytherc17852e2011-01-17 22:23:24 +010023#include <mtp_pcap.h>
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +010024
Harald Welteff397ed2011-05-08 10:29:23 +020025#include <osmocom/core/talloc.h>
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +010026
27#include <sys/socket.h>
28#include <arpa/inet.h>
29
30#include <string.h>
31#include <unistd.h>
32
Holger Hans Peter Freyther718d4ba2011-02-25 19:47:55 +010033#define SCTP_PPID_M2UA 2
34
Holger Hans Peter Freytherab79b9b2011-08-10 06:11:39 +020035
36int sctp_m2ua_conn_count(struct sctp_m2ua_transport *trans)
37{
38 int count = 0;
39 struct sctp_m2ua_conn *conn;
40
41 llist_for_each_entry(conn, &trans->conns, entry)
42 count += 1;
43
44 return count;
45}
46
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +010047static struct mtp_m2ua_link *find_m2ua_link(struct sctp_m2ua_transport *trans, int link_index)
48{
49 struct mtp_m2ua_link *link;
50 link_index = link_index;
51
52 llist_for_each_entry(link, &trans->links, entry) {
53 if (link->link_index == link_index)
54 return link;
55 }
56
57 return NULL;
58}
59
Holger Hans Peter Freyther4c1eb0e2011-01-22 15:52:07 +010060static void link_down(struct mtp_link *link)
61{
62 rate_ctr_inc(&link->ctrg->ctr[MTP_LNK_ERROR]);
63 mtp_link_down(link);
64}
65
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +010066static void m2ua_conn_destroy(struct sctp_m2ua_conn *conn)
67{
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +010068 struct mtp_m2ua_link *link;
69
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +010070 close(conn->queue.bfd.fd);
Harald Welteff397ed2011-05-08 10:29:23 +020071 osmo_fd_unregister(&conn->queue.bfd);
72 osmo_wqueue_clear(&conn->queue);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +010073 llist_del(&conn->entry);
74
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +010075 llist_for_each_entry(link, &conn->trans->links, entry) {
76 if (link->conn != conn)
77 continue;
78
79 if (link->established)
80 link_down(link->base);
81 link->established = 0;
82 link->asp_active = 0;
Holger Hans Peter Freyther4cee7c02011-02-17 18:41:33 +010083 link->active = 0;
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +010084 link->conn = NULL;
85 }
86
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +010087 talloc_free(conn);
88
89 #warning "Notify any other AS(P) for failover scenario"
90}
91
92static int m2ua_conn_send(struct sctp_m2ua_conn *conn,
93 struct m2ua_msg *m2ua,
94 struct sctp_sndrcvinfo *info)
95{
96 struct msgb *msg;
97 msg = m2ua_to_msg(m2ua);
98 if (!msg)
99 return -1;
100
101 /* save the OOB data in front of the message */
102 msg->l2h = msg->data;
103 msgb_push(msg, sizeof(*info));
104 memcpy(msg->data, info, sizeof(*info));
105
Harald Welteff397ed2011-05-08 10:29:23 +0200106 if (osmo_wqueue_enqueue(&conn->queue, msg) != 0) {
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100107 LOGP(DINP, LOGL_ERROR, "Failed to enqueue.\n");
108 msgb_free(msg);
109 return -1;
110 }
111
112 return 0;
113}
114
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100115static int m2ua_conn_send_ntfy(struct mtp_m2ua_link *link,
116 struct sctp_m2ua_conn *conn,
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100117 struct sctp_sndrcvinfo *info)
118{
119 struct m2ua_msg *msg;
120 uint16_t state[2];
Holger Hans Peter Freyther41df6c52011-02-17 03:30:22 +0100121 uint32_t ident;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100122 int rc;
123
124 msg = m2ua_msg_alloc();
125 if (!msg)
126 return -1;
127 msg->hdr.msg_class = M2UA_CLS_MGMT;
128 msg->hdr.msg_type = M2UA_MGMT_NTFY;
129
130 /* state change */
131 state[0] = ntohs(M2UA_STP_AS_STATE_CHG);
132
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100133 if (link->asp_active)
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100134 state[1] = ntohs(M2UA_STP_AS_ACTIVE);
135 else
136 state[1] = ntohs(M2UA_STP_AS_INACTIVE);
137
138 m2ua_msg_add_data(msg, MUA_TAG_STATUS, 4, (uint8_t *) state);
139 m2ua_msg_add_data(msg, MUA_TAG_ASP_IDENT, 4, conn->asp_ident);
Holger Hans Peter Freyther41df6c52011-02-17 03:30:22 +0100140
141 ident = htonl(link->link_index);
142 m2ua_msg_add_data(msg, MUA_TAG_IDENT_INT, 4, (uint8_t *) &ident);
143
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100144 rc = m2ua_conn_send(conn, msg, info);
145 m2ua_msg_free(msg);
146
147 return rc;
148}
149
150static int m2ua_handle_asp_ack(struct sctp_m2ua_conn *conn,
151 struct m2ua_msg *m2ua,
152 struct sctp_sndrcvinfo *info)
153{
Holger Hans Peter Freytherf2312cb2011-08-10 06:21:08 +0200154 struct sctp_m2ua_transport *trans = conn->trans;
155 struct sctp_m2ua_conn *tmp;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100156 struct m2ua_msg_part *asp_ident;
157 struct m2ua_msg *ack;
158
159 asp_ident = m2ua_msg_find_tag(m2ua, MUA_TAG_ASP_IDENT);
160 if (!asp_ident) {
161 LOGP(DINP, LOGL_ERROR, "ASP UP lacks ASP IDENT\n");
162 return -1;
163 }
164 if (asp_ident->len != 4) {
165 LOGP(DINP, LOGL_ERROR, "ASP Ident needs to be four byte.\n");
166 return -1;
167 }
168
169 /* TODO: Better handling for fail over is needed here */
170 ack = m2ua_msg_alloc();
171 if (!ack) {
172 LOGP(DINP, LOGL_ERROR, "Failed to create response\n");
173 return -1;
174 }
175
176 ack->hdr.msg_class = M2UA_CLS_ASPSM;
177 ack->hdr.msg_type = M2UA_ASPSM_UP_ACK;
178 if (m2ua_conn_send(conn, ack, info) != 0) {
179 m2ua_msg_free(ack);
180 return -1;
181 }
182
183 memcpy(conn->asp_ident, asp_ident->dat, 4);
184 conn->asp_up = 1;
185
Holger Hans Peter Freytherf2312cb2011-08-10 06:21:08 +0200186 /* some verification about the ASPs */
187 llist_for_each_entry(tmp, &trans->conns, entry) {
188 if (tmp != conn)
189 continue;
190 if (memcmp(tmp->asp_ident, conn->asp_ident, 4) != 0)
191 continue;
192 LOGP(DINP, LOGL_ERROR,
193 "Two active SCTP conns with %d.%d.%d.%d on %p, %p\n",
194 conn->asp_ident[0], conn->asp_ident[1],
195 conn->asp_ident[2], conn->asp_ident[3],
196 tmp, conn);
197 }
198
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100199 m2ua_msg_free(ack);
200 return 0;
201}
202
203static int m2ua_handle_asp(struct sctp_m2ua_conn *conn,
204 struct m2ua_msg *m2ua, struct sctp_sndrcvinfo *info)
205{
206 switch (m2ua->hdr.msg_type) {
207 case M2UA_ASPSM_UP:
208 m2ua_handle_asp_ack(conn, m2ua, info);
209 break;
210 default:
211 LOGP(DINP, LOGL_ERROR, "Unhandled msg_type %d\n",
212 m2ua->hdr.msg_type);
213 break;
214 }
215
216 return 0;
217}
218
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100219static int m2ua_handle_asptm_act(struct sctp_m2ua_conn *conn,
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100220 struct m2ua_msg *m2ua,
221 struct sctp_sndrcvinfo *info)
222{
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100223 struct m2ua_msg_part *part;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100224 struct m2ua_msg *ack;
225
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100226 ack = m2ua_msg_alloc();
227 if (!ack)
228 return -1;
229
230 ack->hdr.msg_class = M2UA_CLS_ASPTM;
231 ack->hdr.msg_type = M2UA_ASPTM_ACTIV_ACK;
232
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100233 /*
234 * Move things over to this connection now.
235 */
236 llist_for_each_entry(part, &m2ua->headers, entry) {
237 struct mtp_m2ua_link *link;
238 uint32_t interf;
239
240
241 if (part->tag != MUA_TAG_IDENT_INT)
242 continue;
243 if (part->len != 4)
244 continue;
245
246 memcpy(&interf, part->dat, 4);
247 link = find_m2ua_link(conn->trans, ntohl(interf));
248 if (!link) {
249 LOGP(DINP, LOGL_ERROR,
250 "M2UA Link index %d is not configured.\n", ntohl(interf));
251 continue;
252 }
253
254 link->conn = conn;
255 link->asp_active = 1;
256 m2ua_msg_add_data(ack, MUA_TAG_IDENT_INT, 4, (uint8_t *) &interf);
257 }
258
259
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100260 if (m2ua_conn_send(conn, ack, info) != 0) {
261 m2ua_msg_free(ack);
262 return -1;
263 }
264
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100265 /* now again send NTFY on all these links */
266 llist_for_each_entry(part, &m2ua->headers, entry) {
267 struct mtp_m2ua_link *link;
268 uint32_t interf;
269
270
271 if (part->tag != MUA_TAG_IDENT_INT)
272 continue;
273 if (part->len != 4)
274 continue;
275
276 memcpy(&interf, part->dat, 4);
277 link = find_m2ua_link(conn->trans, ntohl(interf));
278 if (!link)
279 continue;
280 m2ua_conn_send_ntfy(link, conn, info);
281 }
282
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100283 m2ua_msg_free(ack);
284 return 0;
285}
286
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100287static int m2ua_handle_asptm(struct sctp_m2ua_conn *conn,
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100288 struct m2ua_msg *m2ua,
289 struct sctp_sndrcvinfo *info)
290{
291 switch (m2ua->hdr.msg_type) {
292 case M2UA_ASPTM_ACTIV:
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100293 m2ua_handle_asptm_act(conn, m2ua, info);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100294 break;
295 default:
296 LOGP(DINP, LOGL_ERROR, "Unhandled msg_type %d\n",
297 m2ua->hdr.msg_type);
298 break;
299 }
300
301 return 0;
302}
303
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100304static int m2ua_handle_state_req(struct mtp_m2ua_link *link,
305 struct sctp_m2ua_conn *conn,
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100306 struct m2ua_msg *m2ua,
307 struct sctp_sndrcvinfo *info)
308{
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100309 struct m2ua_msg_part *state;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100310 struct m2ua_msg *conf;
Holger Hans Peter Freythere62e4b02011-02-17 23:29:41 +0100311 uint32_t index;
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100312 int req;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100313
314 state = m2ua_msg_find_tag(m2ua, M2UA_TAG_STATE_REQ);
315 if (!state || state->len != 4) {
316 LOGP(DINP, LOGL_ERROR, "Mandantory state request not present.\n");
317 return -1;
318 }
319
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100320 memcpy(&req, state->dat, 4);
321 req = ntohl(req);
322
323 switch (req) {
324 case M2UA_STATUS_EMER_SET:
325 conf = m2ua_msg_alloc();
326 if (!conf)
327 return -1;
328
Holger Hans Peter Freythere62e4b02011-02-17 23:29:41 +0100329 index = htonl(link->link_index);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100330 conf->hdr.msg_class = M2UA_CLS_MAUP;
331 conf->hdr.msg_type = M2UA_MAUP_STATE_CON;
Holger Hans Peter Freythere62e4b02011-02-17 23:29:41 +0100332 m2ua_msg_add_data(conf, MUA_TAG_IDENT_INT, 4, (uint8_t *) &index);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100333 m2ua_msg_add_data(conf, M2UA_TAG_STATE_REQ, 4, (uint8_t *) &req);
334 if (m2ua_conn_send(conn, conf, info) != 0) {
335 m2ua_msg_free(conf);
336 return -1;
337 }
338 m2ua_msg_free(conf);
Holger Hans Peter Freyther4cee7c02011-02-17 18:41:33 +0100339
340 LOGP(DINP, LOGL_NOTICE, "M2UA link-index %d is running.\n", link->link_index);
341 link->active = 1;
342 mtp_link_up(link->base);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100343 break;
344 default:
345 LOGP(DINP, LOGL_ERROR, "Unknown STATE Request: %d\n", req);
346 break;
347 }
348
349 return 0;
350}
351
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100352static int m2ua_handle_est_req(struct mtp_m2ua_link *link,
353 struct sctp_m2ua_conn *conn,
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100354 struct m2ua_msg *m2ua,
355 struct sctp_sndrcvinfo *info)
356{
Holger Hans Peter Freythere62e4b02011-02-17 23:29:41 +0100357 uint32_t index;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100358 struct m2ua_msg *conf;
359
360 conf = m2ua_msg_alloc();
361 if (!conf)
362 return -1;
363
364 conf->hdr.msg_class = M2UA_CLS_MAUP;
365 conf->hdr.msg_type = M2UA_MAUP_EST_CON;
366
Holger Hans Peter Freythere62e4b02011-02-17 23:29:41 +0100367 index = htonl(link->link_index);
368 m2ua_msg_add_data(conf, MUA_TAG_IDENT_INT, 4, (uint8_t *) &index);
369
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100370 if (m2ua_conn_send(conn, conf, info) != 0) {
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100371 link->established = 0;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100372 m2ua_msg_free(conf);
373 return -1;
374 }
375
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100376 link->established = 1;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100377 m2ua_msg_free(conf);
378 return 0;
379}
380
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100381static int m2ua_handle_rel_req(struct mtp_m2ua_link *link,
382 struct sctp_m2ua_conn *conn,
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100383 struct m2ua_msg *m2ua,
384 struct sctp_sndrcvinfo *info)
385{
Holger Hans Peter Freythere62e4b02011-02-17 23:29:41 +0100386 uint32_t index;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100387 struct m2ua_msg *conf;
388
389 conf = m2ua_msg_alloc();
390 if (!conf)
391 return -1;
392
393 conf->hdr.msg_class = M2UA_CLS_MAUP;
394 conf->hdr.msg_type = M2UA_MAUP_REL_CON;
395
Holger Hans Peter Freythere62e4b02011-02-17 23:29:41 +0100396 index = htonl(link->link_index);
397 m2ua_msg_add_data(conf, MUA_TAG_IDENT_INT, 4, (uint8_t *) &index);
398
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100399 if (m2ua_conn_send(conn, conf, info) != 0) {
400 m2ua_msg_free(conf);
401 return -1;
402 }
403
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100404 link->established = 0;
Holger Hans Peter Freyther4cee7c02011-02-17 18:41:33 +0100405 link->active = 0;
Holger Hans Peter Freyther123147a2011-03-03 00:58:44 +0100406 LOGP(DINP, LOGL_NOTICE, "M2UA/Link link-index %d is released.\n", link->link_index);
Holger Hans Peter Freyther6c0b2e52011-02-17 02:18:38 +0100407 link_down(link->base);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100408 m2ua_msg_free(conf);
409 return 0;
410}
411
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100412static int m2ua_handle_data(struct mtp_m2ua_link *_link,
413 struct sctp_m2ua_conn *conn,
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100414 struct m2ua_msg *m2ua,
415 struct sctp_sndrcvinfo *info)
416{
417 struct msgb *msg;
418 struct m2ua_msg_part *data;
Holger Hans Peter Freytherc17852e2011-01-17 22:23:24 +0100419 struct mtp_link *link;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100420
421 data = m2ua_msg_find_tag(m2ua, M2UA_TAG_DATA);
422 if (!data) {
423 LOGP(DINP, LOGL_ERROR, "No DATA in DATA message.\n");
424 return -1;
425 }
426
427 if (data->len > 2048) {
428 LOGP(DINP, LOGL_ERROR, "TOO much data for us to handle.\n");
429 return -1;
430 }
431
432 msg = msgb_alloc(2048, "m2ua-data");
433 if (!msg) {
434 LOGP(DINP, LOGL_ERROR, "Failed to allocate storage.\n");
435 return -1;
436 }
437
438 msg->l2h = msgb_put(msg, data->len);
439 memcpy(msg->l2h, data->dat, data->len);
Holger Hans Peter Freytherc17852e2011-01-17 22:23:24 +0100440
Holger Hans Peter Freyther6c0b2e52011-02-17 02:18:38 +0100441 link = _link->base;
Holger Hans Peter Freytherea5ce232011-01-23 23:31:26 +0100442 if (!link->blocked) {
443 mtp_handle_pcap(link, NET_IN, msg->l2h, msgb_l2len(msg));
444 mtp_link_set_data(link, msg);
445 }
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100446 msgb_free(msg);
447
448 return 0;
449}
450
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100451static int m2ua_handle_maup(struct mtp_m2ua_link *link,
452 struct sctp_m2ua_conn *conn,
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100453 struct m2ua_msg *m2ua,
454 struct sctp_sndrcvinfo *info)
455{
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100456 if (!link) {
457 LOGP(DINP, LOGL_ERROR, "Link is required.\n");
458 return -1;
459 }
460
Holger Hans Peter Freythera79aff32011-08-10 06:40:17 +0200461 /* fixup for a broken MSC */
462 if (!link->conn && m2ua->hdr.msg_type == M2UA_MAUP_STATE_REQ) {
463 LOGP(DINP, LOGL_NOTICE,
464 "No ASP Activate but no connection is on link-index %d.\n",
465 link->link_index);
466 link->conn = conn;
467 link->asp_active = 1;
468 }
469
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100470 if (link->conn != conn) {
471 LOGP(DINP, LOGL_ERROR,
472 "Someone forgot the ASP Activate on link-index %d\n",
473 link->link_index);
474 return -1;
475 }
476
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100477 switch (m2ua->hdr.msg_type) {
478 case M2UA_MAUP_STATE_REQ:
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100479 m2ua_handle_state_req(link, conn, m2ua, info);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100480 break;
481 case M2UA_MAUP_EST_REQ:
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100482 m2ua_handle_est_req(link, conn, m2ua, info);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100483 break;
484 case M2UA_MAUP_REL_REQ:
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100485 m2ua_handle_rel_req(link, conn, m2ua, info);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100486 break;
487 case M2UA_MAUP_DATA:
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100488 m2ua_handle_data(link, conn, m2ua, info);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100489 break;
490 default:
491 LOGP(DINP, LOGL_ERROR, "Unhandled msg_type %d\n",
492 m2ua->hdr.msg_type);
493 break;
494 }
495
496 return 0;
497}
498
499static int m2ua_handle_mgmt(struct sctp_m2ua_conn *conn,
500 struct m2ua_msg *m2ua, struct sctp_sndrcvinfo *info)
501{
502 switch (m2ua->hdr.msg_type) {
503 case M2UA_MGMT_ERROR:
504 LOGP(DINP, LOGL_ERROR, "We did something wrong. Error...\n");
505 break;
506 case M2UA_MGMT_NTFY:
507 LOGP(DINP, LOGL_NOTICE, "There was a notiy.. but we should only send it.\n");
508 break;
509 }
510
511 return 0;
512}
513
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100514static int m2ua_find_interface(struct m2ua_msg *m2ua, int def)
515{
516 struct m2ua_msg_part *ident;
517
518 ident = m2ua_msg_find_tag(m2ua, MUA_TAG_IDENT_INT);
519 if (ident && ident->len == 4) {
520 memcpy(&def, ident->dat, 4);
521 def = ntohl(def);
522 }
523
524 return def;
525}
526
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100527static int m2ua_conn_handle(struct sctp_m2ua_conn *conn,
528 struct msgb *msg, struct sctp_sndrcvinfo *info)
529{
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100530 struct mtp_m2ua_link *link;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100531 struct m2ua_msg *m2ua;
532 m2ua = m2ua_from_msg(msg->len, msg->data);
533 if (!m2ua) {
534 LOGP(DINP, LOGL_ERROR, "Failed to parse the message.\n");
535 return -1;
536 }
537
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100538 link = find_m2ua_link(conn->trans, m2ua_find_interface(m2ua, 0));
539
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100540 switch (m2ua->hdr.msg_class) {
541 case M2UA_CLS_MGMT:
542 m2ua_handle_mgmt(conn, m2ua, info);
543 break;
544 case M2UA_CLS_ASPSM:
545 m2ua_handle_asp(conn, m2ua, info);
546 break;
547 case M2UA_CLS_ASPTM:
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100548 m2ua_handle_asptm(conn, m2ua, info);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100549 break;
550 case M2UA_CLS_MAUP:
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100551 m2ua_handle_maup(link, conn, m2ua, info);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100552 break;
553 default:
554 LOGP(DINP, LOGL_ERROR, "Unhandled msg_class %d\n",
555 m2ua->hdr.msg_class);
556 break;
557 }
558
559 m2ua_msg_free(m2ua);
560 return 0;
561}
562
Harald Welteff397ed2011-05-08 10:29:23 +0200563static int m2ua_conn_read(struct osmo_fd *fd)
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100564{
565 struct sockaddr_in addr;
566 struct sctp_sndrcvinfo info;
567 socklen_t len = sizeof(addr);
568 struct msgb *msg;
569 int rc;
570
571 msg = msgb_alloc(2048, "m2ua buffer");
572 if (!msg) {
573 LOGP(DINP, LOGL_ERROR, "Failed to allocate buffer.\n");
574 m2ua_conn_destroy(fd->data);
575 return -1;
576 }
577
578 memset(&info, 0, sizeof(info));
579 memset(&addr, 0, sizeof(addr));
580 rc = sctp_recvmsg(fd->fd, msg->data, msg->data_len,
581 (struct sockaddr *) &addr, &len, &info, NULL);
Holger Hans Peter Freytherc5562bd2011-01-26 11:02:42 +0100582 if (rc <= 0) {
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100583 LOGP(DINP, LOGL_ERROR, "Failed to read.\n");
Holger Hans Peter Freythera2938fe2011-02-25 19:48:24 +0100584 msgb_free(msg);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100585 m2ua_conn_destroy(fd->data);
586 return -1;
587 }
588
Holger Hans Peter Freyther718d4ba2011-02-25 19:47:55 +0100589 if (ntohl(info.sinfo_ppid) != SCTP_PPID_M2UA) {
590 LOGP(DINP, LOGL_ERROR, "Only M2UA is allowed on this socket.\n");
591 msgb_free(msg);
592 return -1;
593 }
594
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100595 msgb_put(msg, rc);
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100596 LOGP(DINP, LOGL_DEBUG, "Read %d on stream: %d ssn: %d assoc: %d\n",
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100597 rc, info.sinfo_stream, info.sinfo_ssn, info.sinfo_assoc_id);
598 m2ua_conn_handle(fd->data, msg, &info);
599 msgb_free(msg);
600 return 0;
601}
602
603static int sctp_m2ua_write(struct mtp_link *link, struct msgb *msg)
604{
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100605 struct mtp_m2ua_link *mlink;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100606 struct sctp_sndrcvinfo info;
607 struct m2ua_msg *m2ua;
608 uint32_t interface;
609
Holger Hans Peter Freyther6c0b2e52011-02-17 02:18:38 +0100610 mlink = (struct mtp_m2ua_link *) link->data;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100611
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100612
613 if (!mlink->conn) {
614 LOGP(DINP, LOGL_ERROR, "M2UA write with no ASP for %d/%s of %d/%s.\n",
615 link->nr, link->name, link->set->nr, link->set->name);
Holger Hans Peter Freyther1927e632011-02-15 16:51:43 +0100616 goto clean;
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100617 }
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100618
Holger Hans Peter Freyther4cee7c02011-02-17 18:41:33 +0100619 if (!mlink->asp_active || !mlink->established || !mlink->active) {
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100620 LOGP(DINP, LOGL_ERROR, "ASP not ready for %d/%s of %d/%s.\n",
621 link->nr, link->name, link->set->nr, link->set->name);
Holger Hans Peter Freyther1927e632011-02-15 16:51:43 +0100622 goto clean;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100623 }
624
625 m2ua = m2ua_msg_alloc();
626 if (!m2ua)
Holger Hans Peter Freyther1927e632011-02-15 16:51:43 +0100627 goto clean;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100628
Holger Hans Peter Freyther36260e92011-01-22 17:37:56 +0100629 mtp_handle_pcap(link, NET_OUT, msg->data, msg->len);
Holger Hans Peter Freytherc17852e2011-01-17 22:23:24 +0100630
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100631 m2ua->hdr.msg_class = M2UA_CLS_MAUP;
632 m2ua->hdr.msg_type = M2UA_MAUP_DATA;
633
Holger Hans Peter Freyther7e8ee3a2011-03-02 22:00:24 +0100634 interface = htonl(mlink->link_index);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100635 m2ua_msg_add_data(m2ua, MUA_TAG_IDENT_INT, 4, (uint8_t *) &interface);
636 m2ua_msg_add_data(m2ua, M2UA_TAG_DATA, msg->len, msg->data);
637
638 memset(&info, 0, sizeof(info));
639 info.sinfo_stream = 1;
640 info.sinfo_assoc_id = 1;
Holger Hans Peter Freyther718d4ba2011-02-25 19:47:55 +0100641 info.sinfo_ppid = htonl(SCTP_PPID_M2UA);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100642
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100643 m2ua_conn_send(mlink->conn, m2ua, &info);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100644 m2ua_msg_free(m2ua);
Holger Hans Peter Freyther1927e632011-02-15 16:51:43 +0100645
646clean:
647 msgb_free(msg);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100648 return 0;
649}
650
Harald Welteff397ed2011-05-08 10:29:23 +0200651static int m2ua_conn_write(struct osmo_fd *fd, struct msgb *msg)
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100652{
653 int ret;
654 struct sctp_sndrcvinfo info;
655 memcpy(&info, msg->data, sizeof(info));
656
657 ret = sctp_send(fd->fd, msg->l2h, msgb_l2len(msg),
658 &info, 0);
659
660 if (ret != msgb_l2len(msg))
661 LOGP(DINP, LOGL_ERROR, "Failed to send %d.\n", ret);
662
663 return 0;
664}
665
Harald Welteff397ed2011-05-08 10:29:23 +0200666static int sctp_trans_accept(struct osmo_fd *fd, unsigned int what)
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100667{
668 struct sctp_event_subscribe events;
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100669 struct sctp_m2ua_transport *trans;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100670 struct sctp_m2ua_conn *conn;
671 struct sockaddr_in addr;
672 socklen_t len;
Holger Hans Peter Freytherab79b9b2011-08-10 06:11:39 +0200673 int s, ret, count;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100674
675 len = sizeof(addr);
676 s = accept(fd->fd, (struct sockaddr *) &addr, &len);
677 if (s < 0) {
678 LOGP(DINP, LOGL_ERROR, "Failed to accept.\n");
679 return -1;
680 }
681
682 trans = fd->data;
683 if (!trans->started) {
684 LOGP(DINP, LOGL_NOTICE, "The link is not started.\n");
685 close(s);
686 return -1;
687 }
688
Holger Hans Peter Freyther0e6cbc62011-02-25 19:42:51 +0100689 memset(&events, 0, sizeof(events));
690 events.sctp_data_io_event = 1;
691 ret = setsockopt(s, SOL_SCTP, SCTP_EVENTS, &events, sizeof(events));
692 if (ret != 0) {
693 LOGP(DINP, LOGL_ERROR, "Failed to enable SCTP Events. Closing socket.\n");
694 close(s);
695 return -1;
696 }
697
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100698 LOGP(DINP, LOGL_NOTICE, "Got a new SCTP connection.\n");
699 conn = talloc_zero(fd->data, struct sctp_m2ua_conn);
700 if (!conn) {
701 LOGP(DINP, LOGL_ERROR, "Failed to create.\n");
702 close(s);
703 return -1;
704 }
705
706 conn->trans = trans;
707
Harald Welteff397ed2011-05-08 10:29:23 +0200708 osmo_wqueue_init(&conn->queue, 10);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100709 conn->queue.bfd.fd = s;
710 conn->queue.bfd.data = conn;
711 conn->queue.bfd.when = BSC_FD_READ;
712 conn->queue.read_cb = m2ua_conn_read;
713 conn->queue.write_cb = m2ua_conn_write;
714
Harald Welteff397ed2011-05-08 10:29:23 +0200715 if (osmo_fd_register(&conn->queue.bfd) != 0) {
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100716 LOGP(DINP, LOGL_ERROR, "Failed to register.\n");
717 close(s);
718 talloc_free(conn);
719 return -1;
720 }
721
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100722 llist_add_tail(&conn->entry, &trans->conns);
Holger Hans Peter Freytherab79b9b2011-08-10 06:11:39 +0200723
724
725 count = sctp_m2ua_conn_count(trans);
726 LOGP(DINP, LOGL_NOTICE, "Now having %d SCTP connection(s).\n", count);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100727 return 0;
728}
729
730static int sctp_m2ua_dummy(struct mtp_link *link)
731{
732 return 0;
733}
734
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100735static int sctp_m2ua_start(struct mtp_link *_link)
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100736{
Holger Hans Peter Freyther6c0b2e52011-02-17 02:18:38 +0100737 struct mtp_m2ua_link *link = (struct mtp_m2ua_link *) _link->data;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100738
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100739 link->transport->started = 1;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100740 return 0;
741}
742
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100743static int sctp_m2ua_reset(struct mtp_link *_link)
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100744{
Holger Hans Peter Freyther6c0b2e52011-02-17 02:18:38 +0100745 struct mtp_m2ua_link *link = (struct mtp_m2ua_link *) _link->data;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100746
Holger Hans Peter Freyther7c6feca2011-02-17 15:15:28 +0100747 /*
748 * TODO: Send a Release Indication? Send NTFY to other ASPs to
749 * ask them to activate the link? What should we do here? Right
750 * now do exactly nothing.
751 */
752 LOGP(DINP, LOGL_ERROR,
753 "M2UA link-index %d not doing the reset.\n", link->link_index);
754
755 if (link->conn && link->asp_active && link->established)
756 mtp_link_start_link_test(_link);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100757
758 return 0;
759}
760
Holger Hans Peter Freyther71760302011-02-22 20:57:08 +0100761struct sctp_m2ua_transport *sctp_m2ua_transp_create(struct bsc_data *bsc)
762{
763 struct sctp_m2ua_transport *trans;
764
765 trans = talloc_zero(bsc, struct sctp_m2ua_transport);
766 if (!trans) {
767 LOGP(DINP, LOGL_ERROR, "Remove the talloc.\n");
768 return NULL;
769 }
770
771 INIT_LLIST_HEAD(&trans->conns);
772 INIT_LLIST_HEAD(&trans->links);
773
774
775 return trans;
776}
777
778int sctp_m2ua_transport_bind(struct sctp_m2ua_transport *trans,
779 const char *ip, int port)
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100780{
781 int sctp;
782 struct sockaddr_in addr;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100783
784 sctp = socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP);
785 if (!sctp) {
786 LOGP(DINP, LOGL_ERROR, "Failed to create socket.\n");
Holger Hans Peter Freyther71760302011-02-22 20:57:08 +0100787 return -1;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100788 }
789
790 memset(&addr, 0, sizeof(addr));
791 addr.sin_family = AF_INET;
792 addr.sin_port = htons(port);
793 addr.sin_addr.s_addr = inet_addr(ip);
794
795 if (bind(sctp, (struct sockaddr *) &addr, sizeof(addr)) != 0) {
796 LOGP(DINP, LOGL_ERROR, "Failed to bind.\n");
797 close(sctp);
Holger Hans Peter Freyther71760302011-02-22 20:57:08 +0100798 return -2;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100799 }
800
801 if (listen(sctp, 1) != 0) {
802 LOGP(DINP, LOGL_ERROR, "Failed to listen.\n");
803 close(sctp);
Holger Hans Peter Freyther71760302011-02-22 20:57:08 +0100804 return -3;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100805 }
806
807 int on = 1;
808 setsockopt(sctp, SOL_SCTP, 112, &on, sizeof(on));
809
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100810 trans->bsc.fd = sctp;
811 trans->bsc.data = trans;
812 trans->bsc.cb = sctp_trans_accept;
813 trans->bsc.when = BSC_FD_READ;
814
Harald Welteff397ed2011-05-08 10:29:23 +0200815 if (osmo_fd_register(&trans->bsc) != 0) {
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100816 LOGP(DINP, LOGL_ERROR, "Failed to register the fd.\n");
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100817 close(sctp);
Holger Hans Peter Freyther71760302011-02-22 20:57:08 +0100818 return -4;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100819 }
820
Holger Hans Peter Freyther71760302011-02-22 20:57:08 +0100821 return 0;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100822}
823
Holger Hans Peter Freyther71760302011-02-22 20:57:08 +0100824struct mtp_m2ua_link *mtp_m2ua_link_init(struct mtp_link *blnk)
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100825{
Holger Hans Peter Freyther71760302011-02-22 20:57:08 +0100826 struct sctp_m2ua_transport *trans;
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100827 struct mtp_m2ua_link *lnk;
828
Holger Hans Peter Freyther6c0b2e52011-02-17 02:18:38 +0100829 lnk = talloc_zero(blnk, struct mtp_m2ua_link);
830 if (!lnk) {
831 LOGP(DINP, LOGL_ERROR, "Failed to allocate.\n");
Holger Hans Peter Freyther6c0b2e52011-02-17 02:18:38 +0100832 return NULL;
833 }
834
835 /* make sure we can resolve it both ways */
836 lnk->base = blnk;
837 blnk->data = lnk;
838 blnk->type = SS7_LTYPE_M2UA;
839
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100840 /* remember we have a link here */
Holger Hans Peter Freyther71760302011-02-22 20:57:08 +0100841 trans = blnk->set->bsc->m2ua_trans;
Holger Hans Peter Freyther169a1a92011-02-22 15:45:52 +0100842 llist_add_tail(&lnk->entry, &trans->links);
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100843
Holger Hans Peter Freyther6c0b2e52011-02-17 02:18:38 +0100844 lnk->base->shutdown = sctp_m2ua_reset;
845 lnk->base->clear_queue = sctp_m2ua_dummy;
846 lnk->base->reset = sctp_m2ua_reset;
847 lnk->base->start = sctp_m2ua_start;
848 lnk->base->write = sctp_m2ua_write;
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100849
Holger Hans Peter Freytherb27c9622011-02-16 23:47:25 +0100850 lnk->transport = trans;
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100851 return lnk;
852}