blob: 017f65e1aa5e12ea5351fae395355fb9aa2537a5 [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 Freytherf7ce2c62011-02-15 15:45:32 +010035static struct mtp_m2ua_link *find_m2ua_link(struct sctp_m2ua_transport *trans, int link_index)
36{
37 struct mtp_m2ua_link *link;
38 link_index = link_index;
39
40 llist_for_each_entry(link, &trans->links, entry) {
41 if (link->link_index == link_index)
42 return link;
43 }
44
45 return NULL;
46}
47
Holger Hans Peter Freyther4c1eb0e2011-01-22 15:52:07 +010048static void link_down(struct mtp_link *link)
49{
50 rate_ctr_inc(&link->ctrg->ctr[MTP_LNK_ERROR]);
51 mtp_link_down(link);
52}
53
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +010054static void m2ua_conn_destroy(struct sctp_m2ua_conn *conn)
55{
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +010056 struct mtp_m2ua_link *link;
57
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +010058 close(conn->queue.bfd.fd);
Harald Welteff397ed2011-05-08 10:29:23 +020059 osmo_fd_unregister(&conn->queue.bfd);
60 osmo_wqueue_clear(&conn->queue);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +010061 llist_del(&conn->entry);
62
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +010063 llist_for_each_entry(link, &conn->trans->links, entry) {
64 if (link->conn != conn)
65 continue;
66
67 if (link->established)
68 link_down(link->base);
69 link->established = 0;
70 link->asp_active = 0;
Holger Hans Peter Freyther4cee7c02011-02-17 18:41:33 +010071 link->active = 0;
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +010072 link->conn = NULL;
73 }
74
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +010075 talloc_free(conn);
76
77 #warning "Notify any other AS(P) for failover scenario"
78}
79
80static int m2ua_conn_send(struct sctp_m2ua_conn *conn,
81 struct m2ua_msg *m2ua,
82 struct sctp_sndrcvinfo *info)
83{
84 struct msgb *msg;
85 msg = m2ua_to_msg(m2ua);
86 if (!msg)
87 return -1;
88
89 /* save the OOB data in front of the message */
90 msg->l2h = msg->data;
91 msgb_push(msg, sizeof(*info));
92 memcpy(msg->data, info, sizeof(*info));
93
Harald Welteff397ed2011-05-08 10:29:23 +020094 if (osmo_wqueue_enqueue(&conn->queue, msg) != 0) {
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +010095 LOGP(DINP, LOGL_ERROR, "Failed to enqueue.\n");
96 msgb_free(msg);
97 return -1;
98 }
99
100 return 0;
101}
102
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100103static int m2ua_conn_send_ntfy(struct mtp_m2ua_link *link,
104 struct sctp_m2ua_conn *conn,
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100105 struct sctp_sndrcvinfo *info)
106{
107 struct m2ua_msg *msg;
108 uint16_t state[2];
Holger Hans Peter Freyther41df6c52011-02-17 03:30:22 +0100109 uint32_t ident;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100110 int rc;
111
112 msg = m2ua_msg_alloc();
113 if (!msg)
114 return -1;
115 msg->hdr.msg_class = M2UA_CLS_MGMT;
116 msg->hdr.msg_type = M2UA_MGMT_NTFY;
117
118 /* state change */
119 state[0] = ntohs(M2UA_STP_AS_STATE_CHG);
120
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100121 if (link->asp_active)
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100122 state[1] = ntohs(M2UA_STP_AS_ACTIVE);
123 else
124 state[1] = ntohs(M2UA_STP_AS_INACTIVE);
125
126 m2ua_msg_add_data(msg, MUA_TAG_STATUS, 4, (uint8_t *) state);
127 m2ua_msg_add_data(msg, MUA_TAG_ASP_IDENT, 4, conn->asp_ident);
Holger Hans Peter Freyther41df6c52011-02-17 03:30:22 +0100128
129 ident = htonl(link->link_index);
130 m2ua_msg_add_data(msg, MUA_TAG_IDENT_INT, 4, (uint8_t *) &ident);
131
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100132 rc = m2ua_conn_send(conn, msg, info);
133 m2ua_msg_free(msg);
134
135 return rc;
136}
137
138static int m2ua_handle_asp_ack(struct sctp_m2ua_conn *conn,
139 struct m2ua_msg *m2ua,
140 struct sctp_sndrcvinfo *info)
141{
142 struct m2ua_msg_part *asp_ident;
143 struct m2ua_msg *ack;
144
145 asp_ident = m2ua_msg_find_tag(m2ua, MUA_TAG_ASP_IDENT);
146 if (!asp_ident) {
147 LOGP(DINP, LOGL_ERROR, "ASP UP lacks ASP IDENT\n");
148 return -1;
149 }
150 if (asp_ident->len != 4) {
151 LOGP(DINP, LOGL_ERROR, "ASP Ident needs to be four byte.\n");
152 return -1;
153 }
154
155 /* TODO: Better handling for fail over is needed here */
156 ack = m2ua_msg_alloc();
157 if (!ack) {
158 LOGP(DINP, LOGL_ERROR, "Failed to create response\n");
159 return -1;
160 }
161
162 ack->hdr.msg_class = M2UA_CLS_ASPSM;
163 ack->hdr.msg_type = M2UA_ASPSM_UP_ACK;
164 if (m2ua_conn_send(conn, ack, info) != 0) {
165 m2ua_msg_free(ack);
166 return -1;
167 }
168
169 memcpy(conn->asp_ident, asp_ident->dat, 4);
170 conn->asp_up = 1;
171
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100172 m2ua_msg_free(ack);
173 return 0;
174}
175
176static int m2ua_handle_asp(struct sctp_m2ua_conn *conn,
177 struct m2ua_msg *m2ua, struct sctp_sndrcvinfo *info)
178{
179 switch (m2ua->hdr.msg_type) {
180 case M2UA_ASPSM_UP:
181 m2ua_handle_asp_ack(conn, m2ua, info);
182 break;
183 default:
184 LOGP(DINP, LOGL_ERROR, "Unhandled msg_type %d\n",
185 m2ua->hdr.msg_type);
186 break;
187 }
188
189 return 0;
190}
191
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100192static int m2ua_handle_asptm_act(struct sctp_m2ua_conn *conn,
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100193 struct m2ua_msg *m2ua,
194 struct sctp_sndrcvinfo *info)
195{
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100196 struct m2ua_msg_part *part;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100197 struct m2ua_msg *ack;
198
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100199 ack = m2ua_msg_alloc();
200 if (!ack)
201 return -1;
202
203 ack->hdr.msg_class = M2UA_CLS_ASPTM;
204 ack->hdr.msg_type = M2UA_ASPTM_ACTIV_ACK;
205
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100206 /*
207 * Move things over to this connection now.
208 */
209 llist_for_each_entry(part, &m2ua->headers, entry) {
210 struct mtp_m2ua_link *link;
211 uint32_t interf;
212
213
214 if (part->tag != MUA_TAG_IDENT_INT)
215 continue;
216 if (part->len != 4)
217 continue;
218
219 memcpy(&interf, part->dat, 4);
220 link = find_m2ua_link(conn->trans, ntohl(interf));
221 if (!link) {
222 LOGP(DINP, LOGL_ERROR,
223 "M2UA Link index %d is not configured.\n", ntohl(interf));
224 continue;
225 }
226
227 link->conn = conn;
228 link->asp_active = 1;
229 m2ua_msg_add_data(ack, MUA_TAG_IDENT_INT, 4, (uint8_t *) &interf);
230 }
231
232
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100233 if (m2ua_conn_send(conn, ack, info) != 0) {
234 m2ua_msg_free(ack);
235 return -1;
236 }
237
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100238 /* now again send NTFY on all these links */
239 llist_for_each_entry(part, &m2ua->headers, entry) {
240 struct mtp_m2ua_link *link;
241 uint32_t interf;
242
243
244 if (part->tag != MUA_TAG_IDENT_INT)
245 continue;
246 if (part->len != 4)
247 continue;
248
249 memcpy(&interf, part->dat, 4);
250 link = find_m2ua_link(conn->trans, ntohl(interf));
251 if (!link)
252 continue;
253 m2ua_conn_send_ntfy(link, conn, info);
254 }
255
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100256 m2ua_msg_free(ack);
257 return 0;
258}
259
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100260static int m2ua_handle_asptm(struct sctp_m2ua_conn *conn,
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100261 struct m2ua_msg *m2ua,
262 struct sctp_sndrcvinfo *info)
263{
264 switch (m2ua->hdr.msg_type) {
265 case M2UA_ASPTM_ACTIV:
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100266 m2ua_handle_asptm_act(conn, m2ua, info);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100267 break;
268 default:
269 LOGP(DINP, LOGL_ERROR, "Unhandled msg_type %d\n",
270 m2ua->hdr.msg_type);
271 break;
272 }
273
274 return 0;
275}
276
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100277static int m2ua_handle_state_req(struct mtp_m2ua_link *link,
278 struct sctp_m2ua_conn *conn,
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100279 struct m2ua_msg *m2ua,
280 struct sctp_sndrcvinfo *info)
281{
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100282 struct m2ua_msg_part *state;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100283 struct m2ua_msg *conf;
Holger Hans Peter Freythere62e4b02011-02-17 23:29:41 +0100284 uint32_t index;
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100285 int req;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100286
Holger Hans Peter Freyther5960ba32011-03-02 21:56:03 +0100287 /* fixup for a broken MSC */
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100288 if (link->conn != conn) {
Holger Hans Peter Freyther5960ba32011-03-02 21:56:03 +0100289 if (!link->conn) {
290 LOGP(DINP, LOGL_NOTICE,
291 "No ASP Activate but no connection is on link-index %d.\n",
292 link->link_index);
293 link->conn = conn;
294 link->asp_active = 1;
295 } else {
296 LOGP(DINP, LOGL_ERROR,
297 "Someone forgot the ASP Activate on link-index %d\n",
298 link->link_index);
299 return -1;
300 }
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100301 }
302
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100303 state = m2ua_msg_find_tag(m2ua, M2UA_TAG_STATE_REQ);
304 if (!state || state->len != 4) {
305 LOGP(DINP, LOGL_ERROR, "Mandantory state request not present.\n");
306 return -1;
307 }
308
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100309 memcpy(&req, state->dat, 4);
310 req = ntohl(req);
311
312 switch (req) {
313 case M2UA_STATUS_EMER_SET:
314 conf = m2ua_msg_alloc();
315 if (!conf)
316 return -1;
317
Holger Hans Peter Freythere62e4b02011-02-17 23:29:41 +0100318 index = htonl(link->link_index);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100319 conf->hdr.msg_class = M2UA_CLS_MAUP;
320 conf->hdr.msg_type = M2UA_MAUP_STATE_CON;
Holger Hans Peter Freythere62e4b02011-02-17 23:29:41 +0100321 m2ua_msg_add_data(conf, MUA_TAG_IDENT_INT, 4, (uint8_t *) &index);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100322 m2ua_msg_add_data(conf, M2UA_TAG_STATE_REQ, 4, (uint8_t *) &req);
323 if (m2ua_conn_send(conn, conf, info) != 0) {
324 m2ua_msg_free(conf);
325 return -1;
326 }
327 m2ua_msg_free(conf);
Holger Hans Peter Freyther4cee7c02011-02-17 18:41:33 +0100328
329 LOGP(DINP, LOGL_NOTICE, "M2UA link-index %d is running.\n", link->link_index);
330 link->active = 1;
331 mtp_link_up(link->base);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100332 break;
333 default:
334 LOGP(DINP, LOGL_ERROR, "Unknown STATE Request: %d\n", req);
335 break;
336 }
337
338 return 0;
339}
340
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100341static int m2ua_handle_est_req(struct mtp_m2ua_link *link,
342 struct sctp_m2ua_conn *conn,
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100343 struct m2ua_msg *m2ua,
344 struct sctp_sndrcvinfo *info)
345{
Holger Hans Peter Freythere62e4b02011-02-17 23:29:41 +0100346 uint32_t index;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100347 struct m2ua_msg *conf;
348
349 conf = m2ua_msg_alloc();
350 if (!conf)
351 return -1;
352
353 conf->hdr.msg_class = M2UA_CLS_MAUP;
354 conf->hdr.msg_type = M2UA_MAUP_EST_CON;
355
Holger Hans Peter Freythere62e4b02011-02-17 23:29:41 +0100356 index = htonl(link->link_index);
357 m2ua_msg_add_data(conf, MUA_TAG_IDENT_INT, 4, (uint8_t *) &index);
358
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100359 if (m2ua_conn_send(conn, conf, info) != 0) {
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100360 link->established = 0;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100361 m2ua_msg_free(conf);
362 return -1;
363 }
364
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100365 link->established = 1;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100366 m2ua_msg_free(conf);
367 return 0;
368}
369
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100370static int m2ua_handle_rel_req(struct mtp_m2ua_link *link,
371 struct sctp_m2ua_conn *conn,
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100372 struct m2ua_msg *m2ua,
373 struct sctp_sndrcvinfo *info)
374{
Holger Hans Peter Freythere62e4b02011-02-17 23:29:41 +0100375 uint32_t index;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100376 struct m2ua_msg *conf;
377
378 conf = m2ua_msg_alloc();
379 if (!conf)
380 return -1;
381
382 conf->hdr.msg_class = M2UA_CLS_MAUP;
383 conf->hdr.msg_type = M2UA_MAUP_REL_CON;
384
Holger Hans Peter Freythere62e4b02011-02-17 23:29:41 +0100385 index = htonl(link->link_index);
386 m2ua_msg_add_data(conf, MUA_TAG_IDENT_INT, 4, (uint8_t *) &index);
387
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100388 if (m2ua_conn_send(conn, conf, info) != 0) {
389 m2ua_msg_free(conf);
390 return -1;
391 }
392
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100393 link->established = 0;
Holger Hans Peter Freyther4cee7c02011-02-17 18:41:33 +0100394 link->active = 0;
Holger Hans Peter Freyther123147a2011-03-03 00:58:44 +0100395 LOGP(DINP, LOGL_NOTICE, "M2UA/Link link-index %d is released.\n", link->link_index);
Holger Hans Peter Freyther6c0b2e52011-02-17 02:18:38 +0100396 link_down(link->base);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100397 m2ua_msg_free(conf);
398 return 0;
399}
400
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100401static int m2ua_handle_data(struct mtp_m2ua_link *_link,
402 struct sctp_m2ua_conn *conn,
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100403 struct m2ua_msg *m2ua,
404 struct sctp_sndrcvinfo *info)
405{
406 struct msgb *msg;
407 struct m2ua_msg_part *data;
Holger Hans Peter Freytherc17852e2011-01-17 22:23:24 +0100408 struct mtp_link *link;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100409
410 data = m2ua_msg_find_tag(m2ua, M2UA_TAG_DATA);
411 if (!data) {
412 LOGP(DINP, LOGL_ERROR, "No DATA in DATA message.\n");
413 return -1;
414 }
415
416 if (data->len > 2048) {
417 LOGP(DINP, LOGL_ERROR, "TOO much data for us to handle.\n");
418 return -1;
419 }
420
421 msg = msgb_alloc(2048, "m2ua-data");
422 if (!msg) {
423 LOGP(DINP, LOGL_ERROR, "Failed to allocate storage.\n");
424 return -1;
425 }
426
427 msg->l2h = msgb_put(msg, data->len);
428 memcpy(msg->l2h, data->dat, data->len);
Holger Hans Peter Freytherc17852e2011-01-17 22:23:24 +0100429
Holger Hans Peter Freyther6c0b2e52011-02-17 02:18:38 +0100430 link = _link->base;
Holger Hans Peter Freytherea5ce232011-01-23 23:31:26 +0100431 if (!link->blocked) {
432 mtp_handle_pcap(link, NET_IN, msg->l2h, msgb_l2len(msg));
433 mtp_link_set_data(link, msg);
434 }
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100435 msgb_free(msg);
436
437 return 0;
438}
439
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100440static int m2ua_handle_maup(struct mtp_m2ua_link *link,
441 struct sctp_m2ua_conn *conn,
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100442 struct m2ua_msg *m2ua,
443 struct sctp_sndrcvinfo *info)
444{
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100445 if (!link) {
446 LOGP(DINP, LOGL_ERROR, "Link is required.\n");
447 return -1;
448 }
449
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100450 if (link->conn != conn) {
451 LOGP(DINP, LOGL_ERROR,
452 "Someone forgot the ASP Activate on link-index %d\n",
453 link->link_index);
454 return -1;
455 }
456
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100457 switch (m2ua->hdr.msg_type) {
458 case M2UA_MAUP_STATE_REQ:
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100459 m2ua_handle_state_req(link, conn, m2ua, info);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100460 break;
461 case M2UA_MAUP_EST_REQ:
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100462 m2ua_handle_est_req(link, conn, m2ua, info);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100463 break;
464 case M2UA_MAUP_REL_REQ:
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100465 m2ua_handle_rel_req(link, conn, m2ua, info);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100466 break;
467 case M2UA_MAUP_DATA:
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100468 m2ua_handle_data(link, conn, m2ua, info);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100469 break;
470 default:
471 LOGP(DINP, LOGL_ERROR, "Unhandled msg_type %d\n",
472 m2ua->hdr.msg_type);
473 break;
474 }
475
476 return 0;
477}
478
479static int m2ua_handle_mgmt(struct sctp_m2ua_conn *conn,
480 struct m2ua_msg *m2ua, struct sctp_sndrcvinfo *info)
481{
482 switch (m2ua->hdr.msg_type) {
483 case M2UA_MGMT_ERROR:
484 LOGP(DINP, LOGL_ERROR, "We did something wrong. Error...\n");
485 break;
486 case M2UA_MGMT_NTFY:
487 LOGP(DINP, LOGL_NOTICE, "There was a notiy.. but we should only send it.\n");
488 break;
489 }
490
491 return 0;
492}
493
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100494static int m2ua_find_interface(struct m2ua_msg *m2ua, int def)
495{
496 struct m2ua_msg_part *ident;
497
498 ident = m2ua_msg_find_tag(m2ua, MUA_TAG_IDENT_INT);
499 if (ident && ident->len == 4) {
500 memcpy(&def, ident->dat, 4);
501 def = ntohl(def);
502 }
503
504 return def;
505}
506
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100507static int m2ua_conn_handle(struct sctp_m2ua_conn *conn,
508 struct msgb *msg, struct sctp_sndrcvinfo *info)
509{
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100510 struct mtp_m2ua_link *link;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100511 struct m2ua_msg *m2ua;
512 m2ua = m2ua_from_msg(msg->len, msg->data);
513 if (!m2ua) {
514 LOGP(DINP, LOGL_ERROR, "Failed to parse the message.\n");
515 return -1;
516 }
517
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100518 link = find_m2ua_link(conn->trans, m2ua_find_interface(m2ua, 0));
519
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100520 switch (m2ua->hdr.msg_class) {
521 case M2UA_CLS_MGMT:
522 m2ua_handle_mgmt(conn, m2ua, info);
523 break;
524 case M2UA_CLS_ASPSM:
525 m2ua_handle_asp(conn, m2ua, info);
526 break;
527 case M2UA_CLS_ASPTM:
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100528 m2ua_handle_asptm(conn, m2ua, info);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100529 break;
530 case M2UA_CLS_MAUP:
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100531 m2ua_handle_maup(link, conn, m2ua, info);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100532 break;
533 default:
534 LOGP(DINP, LOGL_ERROR, "Unhandled msg_class %d\n",
535 m2ua->hdr.msg_class);
536 break;
537 }
538
539 m2ua_msg_free(m2ua);
540 return 0;
541}
542
Harald Welteff397ed2011-05-08 10:29:23 +0200543static int m2ua_conn_read(struct osmo_fd *fd)
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100544{
545 struct sockaddr_in addr;
546 struct sctp_sndrcvinfo info;
547 socklen_t len = sizeof(addr);
548 struct msgb *msg;
549 int rc;
550
551 msg = msgb_alloc(2048, "m2ua buffer");
552 if (!msg) {
553 LOGP(DINP, LOGL_ERROR, "Failed to allocate buffer.\n");
554 m2ua_conn_destroy(fd->data);
555 return -1;
556 }
557
558 memset(&info, 0, sizeof(info));
559 memset(&addr, 0, sizeof(addr));
560 rc = sctp_recvmsg(fd->fd, msg->data, msg->data_len,
561 (struct sockaddr *) &addr, &len, &info, NULL);
Holger Hans Peter Freytherc5562bd2011-01-26 11:02:42 +0100562 if (rc <= 0) {
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100563 LOGP(DINP, LOGL_ERROR, "Failed to read.\n");
Holger Hans Peter Freythera2938fe2011-02-25 19:48:24 +0100564 msgb_free(msg);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100565 m2ua_conn_destroy(fd->data);
566 return -1;
567 }
568
Holger Hans Peter Freyther718d4ba2011-02-25 19:47:55 +0100569 if (ntohl(info.sinfo_ppid) != SCTP_PPID_M2UA) {
570 LOGP(DINP, LOGL_ERROR, "Only M2UA is allowed on this socket.\n");
571 msgb_free(msg);
572 return -1;
573 }
574
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100575 msgb_put(msg, rc);
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100576 LOGP(DINP, LOGL_DEBUG, "Read %d on stream: %d ssn: %d assoc: %d\n",
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100577 rc, info.sinfo_stream, info.sinfo_ssn, info.sinfo_assoc_id);
578 m2ua_conn_handle(fd->data, msg, &info);
579 msgb_free(msg);
580 return 0;
581}
582
583static int sctp_m2ua_write(struct mtp_link *link, struct msgb *msg)
584{
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100585 struct mtp_m2ua_link *mlink;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100586 struct sctp_sndrcvinfo info;
587 struct m2ua_msg *m2ua;
588 uint32_t interface;
589
Holger Hans Peter Freyther6c0b2e52011-02-17 02:18:38 +0100590 mlink = (struct mtp_m2ua_link *) link->data;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100591
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100592
593 if (!mlink->conn) {
594 LOGP(DINP, LOGL_ERROR, "M2UA write with no ASP for %d/%s of %d/%s.\n",
595 link->nr, link->name, link->set->nr, link->set->name);
Holger Hans Peter Freyther1927e632011-02-15 16:51:43 +0100596 goto clean;
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100597 }
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100598
Holger Hans Peter Freyther4cee7c02011-02-17 18:41:33 +0100599 if (!mlink->asp_active || !mlink->established || !mlink->active) {
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100600 LOGP(DINP, LOGL_ERROR, "ASP not ready for %d/%s of %d/%s.\n",
601 link->nr, link->name, link->set->nr, link->set->name);
Holger Hans Peter Freyther1927e632011-02-15 16:51:43 +0100602 goto clean;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100603 }
604
605 m2ua = m2ua_msg_alloc();
606 if (!m2ua)
Holger Hans Peter Freyther1927e632011-02-15 16:51:43 +0100607 goto clean;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100608
Holger Hans Peter Freyther36260e92011-01-22 17:37:56 +0100609 mtp_handle_pcap(link, NET_OUT, msg->data, msg->len);
Holger Hans Peter Freytherc17852e2011-01-17 22:23:24 +0100610
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100611 m2ua->hdr.msg_class = M2UA_CLS_MAUP;
612 m2ua->hdr.msg_type = M2UA_MAUP_DATA;
613
Holger Hans Peter Freyther7e8ee3a2011-03-02 22:00:24 +0100614 interface = htonl(mlink->link_index);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100615 m2ua_msg_add_data(m2ua, MUA_TAG_IDENT_INT, 4, (uint8_t *) &interface);
616 m2ua_msg_add_data(m2ua, M2UA_TAG_DATA, msg->len, msg->data);
617
618 memset(&info, 0, sizeof(info));
619 info.sinfo_stream = 1;
620 info.sinfo_assoc_id = 1;
Holger Hans Peter Freyther718d4ba2011-02-25 19:47:55 +0100621 info.sinfo_ppid = htonl(SCTP_PPID_M2UA);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100622
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100623 m2ua_conn_send(mlink->conn, m2ua, &info);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100624 m2ua_msg_free(m2ua);
Holger Hans Peter Freyther1927e632011-02-15 16:51:43 +0100625
626clean:
627 msgb_free(msg);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100628 return 0;
629}
630
Harald Welteff397ed2011-05-08 10:29:23 +0200631static int m2ua_conn_write(struct osmo_fd *fd, struct msgb *msg)
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100632{
633 int ret;
634 struct sctp_sndrcvinfo info;
635 memcpy(&info, msg->data, sizeof(info));
636
637 ret = sctp_send(fd->fd, msg->l2h, msgb_l2len(msg),
638 &info, 0);
639
640 if (ret != msgb_l2len(msg))
641 LOGP(DINP, LOGL_ERROR, "Failed to send %d.\n", ret);
642
643 return 0;
644}
645
Harald Welteff397ed2011-05-08 10:29:23 +0200646static int sctp_trans_accept(struct osmo_fd *fd, unsigned int what)
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100647{
648 struct sctp_event_subscribe events;
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100649 struct sctp_m2ua_transport *trans;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100650 struct sctp_m2ua_conn *conn;
651 struct sockaddr_in addr;
652 socklen_t len;
Holger Hans Peter Freyther0e6cbc62011-02-25 19:42:51 +0100653 int s, ret;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100654
655 len = sizeof(addr);
656 s = accept(fd->fd, (struct sockaddr *) &addr, &len);
657 if (s < 0) {
658 LOGP(DINP, LOGL_ERROR, "Failed to accept.\n");
659 return -1;
660 }
661
662 trans = fd->data;
663 if (!trans->started) {
664 LOGP(DINP, LOGL_NOTICE, "The link is not started.\n");
665 close(s);
666 return -1;
667 }
668
Holger Hans Peter Freyther0e6cbc62011-02-25 19:42:51 +0100669 memset(&events, 0, sizeof(events));
670 events.sctp_data_io_event = 1;
671 ret = setsockopt(s, SOL_SCTP, SCTP_EVENTS, &events, sizeof(events));
672 if (ret != 0) {
673 LOGP(DINP, LOGL_ERROR, "Failed to enable SCTP Events. Closing socket.\n");
674 close(s);
675 return -1;
676 }
677
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100678 LOGP(DINP, LOGL_NOTICE, "Got a new SCTP connection.\n");
679 conn = talloc_zero(fd->data, struct sctp_m2ua_conn);
680 if (!conn) {
681 LOGP(DINP, LOGL_ERROR, "Failed to create.\n");
682 close(s);
683 return -1;
684 }
685
686 conn->trans = trans;
687
Harald Welteff397ed2011-05-08 10:29:23 +0200688 osmo_wqueue_init(&conn->queue, 10);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100689 conn->queue.bfd.fd = s;
690 conn->queue.bfd.data = conn;
691 conn->queue.bfd.when = BSC_FD_READ;
692 conn->queue.read_cb = m2ua_conn_read;
693 conn->queue.write_cb = m2ua_conn_write;
694
Harald Welteff397ed2011-05-08 10:29:23 +0200695 if (osmo_fd_register(&conn->queue.bfd) != 0) {
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100696 LOGP(DINP, LOGL_ERROR, "Failed to register.\n");
697 close(s);
698 talloc_free(conn);
699 return -1;
700 }
701
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100702 llist_add_tail(&conn->entry, &trans->conns);
703 return 0;
704}
705
706static int sctp_m2ua_dummy(struct mtp_link *link)
707{
708 return 0;
709}
710
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100711static int sctp_m2ua_start(struct mtp_link *_link)
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100712{
Holger Hans Peter Freyther6c0b2e52011-02-17 02:18:38 +0100713 struct mtp_m2ua_link *link = (struct mtp_m2ua_link *) _link->data;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100714
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100715 link->transport->started = 1;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100716 return 0;
717}
718
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100719static int sctp_m2ua_reset(struct mtp_link *_link)
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100720{
Holger Hans Peter Freyther6c0b2e52011-02-17 02:18:38 +0100721 struct mtp_m2ua_link *link = (struct mtp_m2ua_link *) _link->data;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100722
Holger Hans Peter Freyther7c6feca2011-02-17 15:15:28 +0100723 /*
724 * TODO: Send a Release Indication? Send NTFY to other ASPs to
725 * ask them to activate the link? What should we do here? Right
726 * now do exactly nothing.
727 */
728 LOGP(DINP, LOGL_ERROR,
729 "M2UA link-index %d not doing the reset.\n", link->link_index);
730
731 if (link->conn && link->asp_active && link->established)
732 mtp_link_start_link_test(_link);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100733
734 return 0;
735}
736
Holger Hans Peter Freyther71760302011-02-22 20:57:08 +0100737struct sctp_m2ua_transport *sctp_m2ua_transp_create(struct bsc_data *bsc)
738{
739 struct sctp_m2ua_transport *trans;
740
741 trans = talloc_zero(bsc, struct sctp_m2ua_transport);
742 if (!trans) {
743 LOGP(DINP, LOGL_ERROR, "Remove the talloc.\n");
744 return NULL;
745 }
746
747 INIT_LLIST_HEAD(&trans->conns);
748 INIT_LLIST_HEAD(&trans->links);
749
750
751 return trans;
752}
753
754int sctp_m2ua_transport_bind(struct sctp_m2ua_transport *trans,
755 const char *ip, int port)
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100756{
757 int sctp;
758 struct sockaddr_in addr;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100759
760 sctp = socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP);
761 if (!sctp) {
762 LOGP(DINP, LOGL_ERROR, "Failed to create socket.\n");
Holger Hans Peter Freyther71760302011-02-22 20:57:08 +0100763 return -1;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100764 }
765
766 memset(&addr, 0, sizeof(addr));
767 addr.sin_family = AF_INET;
768 addr.sin_port = htons(port);
769 addr.sin_addr.s_addr = inet_addr(ip);
770
771 if (bind(sctp, (struct sockaddr *) &addr, sizeof(addr)) != 0) {
772 LOGP(DINP, LOGL_ERROR, "Failed to bind.\n");
773 close(sctp);
Holger Hans Peter Freyther71760302011-02-22 20:57:08 +0100774 return -2;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100775 }
776
777 if (listen(sctp, 1) != 0) {
778 LOGP(DINP, LOGL_ERROR, "Failed to listen.\n");
779 close(sctp);
Holger Hans Peter Freyther71760302011-02-22 20:57:08 +0100780 return -3;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100781 }
782
783 int on = 1;
784 setsockopt(sctp, SOL_SCTP, 112, &on, sizeof(on));
785
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100786 trans->bsc.fd = sctp;
787 trans->bsc.data = trans;
788 trans->bsc.cb = sctp_trans_accept;
789 trans->bsc.when = BSC_FD_READ;
790
Harald Welteff397ed2011-05-08 10:29:23 +0200791 if (osmo_fd_register(&trans->bsc) != 0) {
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100792 LOGP(DINP, LOGL_ERROR, "Failed to register the fd.\n");
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100793 close(sctp);
Holger Hans Peter Freyther71760302011-02-22 20:57:08 +0100794 return -4;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100795 }
796
Holger Hans Peter Freyther71760302011-02-22 20:57:08 +0100797 return 0;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100798}
799
Holger Hans Peter Freyther71760302011-02-22 20:57:08 +0100800struct mtp_m2ua_link *mtp_m2ua_link_init(struct mtp_link *blnk)
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100801{
Holger Hans Peter Freyther71760302011-02-22 20:57:08 +0100802 struct sctp_m2ua_transport *trans;
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100803 struct mtp_m2ua_link *lnk;
804
Holger Hans Peter Freyther6c0b2e52011-02-17 02:18:38 +0100805 lnk = talloc_zero(blnk, struct mtp_m2ua_link);
806 if (!lnk) {
807 LOGP(DINP, LOGL_ERROR, "Failed to allocate.\n");
Holger Hans Peter Freyther6c0b2e52011-02-17 02:18:38 +0100808 return NULL;
809 }
810
811 /* make sure we can resolve it both ways */
812 lnk->base = blnk;
813 blnk->data = lnk;
814 blnk->type = SS7_LTYPE_M2UA;
815
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100816 /* remember we have a link here */
Holger Hans Peter Freyther71760302011-02-22 20:57:08 +0100817 trans = blnk->set->bsc->m2ua_trans;
Holger Hans Peter Freyther169a1a92011-02-22 15:45:52 +0100818 llist_add_tail(&lnk->entry, &trans->links);
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100819
Holger Hans Peter Freyther6c0b2e52011-02-17 02:18:38 +0100820 lnk->base->shutdown = sctp_m2ua_reset;
821 lnk->base->clear_queue = sctp_m2ua_dummy;
822 lnk->base->reset = sctp_m2ua_reset;
823 lnk->base->start = sctp_m2ua_start;
824 lnk->base->write = sctp_m2ua_write;
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100825
Holger Hans Peter Freytherb27c9622011-02-16 23:47:25 +0100826 lnk->transport = trans;
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100827 return lnk;
828}