blob: d0609dd660021be5ef0ef67ff7c79a780bb831e4 [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
25#include <osmocore/talloc.h>
26
27#include <sys/socket.h>
28#include <arpa/inet.h>
29
30#include <string.h>
31#include <unistd.h>
32
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +010033static struct mtp_m2ua_link *find_m2ua_link(struct sctp_m2ua_transport *trans, int link_index)
34{
35 struct mtp_m2ua_link *link;
36 link_index = link_index;
37
38 llist_for_each_entry(link, &trans->links, entry) {
39 if (link->link_index == link_index)
40 return link;
41 }
42
43 return NULL;
44}
45
Holger Hans Peter Freyther4c1eb0e2011-01-22 15:52:07 +010046static void link_down(struct mtp_link *link)
47{
48 rate_ctr_inc(&link->ctrg->ctr[MTP_LNK_ERROR]);
49 mtp_link_down(link);
50}
51
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +010052static void m2ua_conn_destroy(struct sctp_m2ua_conn *conn)
53{
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +010054 struct mtp_m2ua_link *link;
55
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +010056 close(conn->queue.bfd.fd);
57 bsc_unregister_fd(&conn->queue.bfd);
58 write_queue_clear(&conn->queue);
59 llist_del(&conn->entry);
60
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +010061 llist_for_each_entry(link, &conn->trans->links, entry) {
62 if (link->conn != conn)
63 continue;
64
65 if (link->established)
66 link_down(link->base);
67 link->established = 0;
68 link->asp_active = 0;
Holger Hans Peter Freyther4cee7c02011-02-17 18:41:33 +010069 link->active = 0;
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +010070 link->conn = NULL;
71 }
72
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +010073 talloc_free(conn);
74
75 #warning "Notify any other AS(P) for failover scenario"
76}
77
78static int m2ua_conn_send(struct sctp_m2ua_conn *conn,
79 struct m2ua_msg *m2ua,
80 struct sctp_sndrcvinfo *info)
81{
82 struct msgb *msg;
83 msg = m2ua_to_msg(m2ua);
84 if (!msg)
85 return -1;
86
87 /* save the OOB data in front of the message */
88 msg->l2h = msg->data;
89 msgb_push(msg, sizeof(*info));
90 memcpy(msg->data, info, sizeof(*info));
91
92 if (write_queue_enqueue(&conn->queue, msg) != 0) {
93 LOGP(DINP, LOGL_ERROR, "Failed to enqueue.\n");
94 msgb_free(msg);
95 return -1;
96 }
97
98 return 0;
99}
100
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100101static int m2ua_conn_send_ntfy(struct mtp_m2ua_link *link,
102 struct sctp_m2ua_conn *conn,
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100103 struct sctp_sndrcvinfo *info)
104{
105 struct m2ua_msg *msg;
106 uint16_t state[2];
Holger Hans Peter Freyther41df6c52011-02-17 03:30:22 +0100107 uint32_t ident;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100108 int rc;
109
110 msg = m2ua_msg_alloc();
111 if (!msg)
112 return -1;
113 msg->hdr.msg_class = M2UA_CLS_MGMT;
114 msg->hdr.msg_type = M2UA_MGMT_NTFY;
115
116 /* state change */
117 state[0] = ntohs(M2UA_STP_AS_STATE_CHG);
118
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100119 if (link->asp_active)
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100120 state[1] = ntohs(M2UA_STP_AS_ACTIVE);
121 else
122 state[1] = ntohs(M2UA_STP_AS_INACTIVE);
123
124 m2ua_msg_add_data(msg, MUA_TAG_STATUS, 4, (uint8_t *) state);
125 m2ua_msg_add_data(msg, MUA_TAG_ASP_IDENT, 4, conn->asp_ident);
Holger Hans Peter Freyther41df6c52011-02-17 03:30:22 +0100126
127 ident = htonl(link->link_index);
128 m2ua_msg_add_data(msg, MUA_TAG_IDENT_INT, 4, (uint8_t *) &ident);
129
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100130 rc = m2ua_conn_send(conn, msg, info);
131 m2ua_msg_free(msg);
132
133 return rc;
134}
135
136static int m2ua_handle_asp_ack(struct sctp_m2ua_conn *conn,
137 struct m2ua_msg *m2ua,
138 struct sctp_sndrcvinfo *info)
139{
140 struct m2ua_msg_part *asp_ident;
141 struct m2ua_msg *ack;
142
143 asp_ident = m2ua_msg_find_tag(m2ua, MUA_TAG_ASP_IDENT);
144 if (!asp_ident) {
145 LOGP(DINP, LOGL_ERROR, "ASP UP lacks ASP IDENT\n");
146 return -1;
147 }
148 if (asp_ident->len != 4) {
149 LOGP(DINP, LOGL_ERROR, "ASP Ident needs to be four byte.\n");
150 return -1;
151 }
152
153 /* TODO: Better handling for fail over is needed here */
154 ack = m2ua_msg_alloc();
155 if (!ack) {
156 LOGP(DINP, LOGL_ERROR, "Failed to create response\n");
157 return -1;
158 }
159
160 ack->hdr.msg_class = M2UA_CLS_ASPSM;
161 ack->hdr.msg_type = M2UA_ASPSM_UP_ACK;
162 if (m2ua_conn_send(conn, ack, info) != 0) {
163 m2ua_msg_free(ack);
164 return -1;
165 }
166
167 memcpy(conn->asp_ident, asp_ident->dat, 4);
168 conn->asp_up = 1;
169
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100170 m2ua_msg_free(ack);
171 return 0;
172}
173
174static int m2ua_handle_asp(struct sctp_m2ua_conn *conn,
175 struct m2ua_msg *m2ua, struct sctp_sndrcvinfo *info)
176{
177 switch (m2ua->hdr.msg_type) {
178 case M2UA_ASPSM_UP:
179 m2ua_handle_asp_ack(conn, m2ua, info);
180 break;
181 default:
182 LOGP(DINP, LOGL_ERROR, "Unhandled msg_type %d\n",
183 m2ua->hdr.msg_type);
184 break;
185 }
186
187 return 0;
188}
189
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100190static int m2ua_handle_asptm_act(struct sctp_m2ua_conn *conn,
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100191 struct m2ua_msg *m2ua,
192 struct sctp_sndrcvinfo *info)
193{
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100194 struct m2ua_msg_part *part;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100195 struct m2ua_msg *ack;
196
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100197 ack = m2ua_msg_alloc();
198 if (!ack)
199 return -1;
200
201 ack->hdr.msg_class = M2UA_CLS_ASPTM;
202 ack->hdr.msg_type = M2UA_ASPTM_ACTIV_ACK;
203
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100204 /*
205 * Move things over to this connection now.
206 */
207 llist_for_each_entry(part, &m2ua->headers, entry) {
208 struct mtp_m2ua_link *link;
209 uint32_t interf;
210
211
212 if (part->tag != MUA_TAG_IDENT_INT)
213 continue;
214 if (part->len != 4)
215 continue;
216
217 memcpy(&interf, part->dat, 4);
218 link = find_m2ua_link(conn->trans, ntohl(interf));
219 if (!link) {
220 LOGP(DINP, LOGL_ERROR,
221 "M2UA Link index %d is not configured.\n", ntohl(interf));
222 continue;
223 }
224
225 link->conn = conn;
226 link->asp_active = 1;
227 m2ua_msg_add_data(ack, MUA_TAG_IDENT_INT, 4, (uint8_t *) &interf);
228 }
229
230
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100231 if (m2ua_conn_send(conn, ack, info) != 0) {
232 m2ua_msg_free(ack);
233 return -1;
234 }
235
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100236 /* now again send NTFY on all these links */
237 llist_for_each_entry(part, &m2ua->headers, entry) {
238 struct mtp_m2ua_link *link;
239 uint32_t interf;
240
241
242 if (part->tag != MUA_TAG_IDENT_INT)
243 continue;
244 if (part->len != 4)
245 continue;
246
247 memcpy(&interf, part->dat, 4);
248 link = find_m2ua_link(conn->trans, ntohl(interf));
249 if (!link)
250 continue;
251 m2ua_conn_send_ntfy(link, conn, info);
252 }
253
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100254 m2ua_msg_free(ack);
255 return 0;
256}
257
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100258static int m2ua_handle_asptm(struct sctp_m2ua_conn *conn,
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100259 struct m2ua_msg *m2ua,
260 struct sctp_sndrcvinfo *info)
261{
262 switch (m2ua->hdr.msg_type) {
263 case M2UA_ASPTM_ACTIV:
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100264 m2ua_handle_asptm_act(conn, m2ua, info);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100265 break;
266 default:
267 LOGP(DINP, LOGL_ERROR, "Unhandled msg_type %d\n",
268 m2ua->hdr.msg_type);
269 break;
270 }
271
272 return 0;
273}
274
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100275static int m2ua_handle_state_req(struct mtp_m2ua_link *link,
276 struct sctp_m2ua_conn *conn,
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100277 struct m2ua_msg *m2ua,
278 struct sctp_sndrcvinfo *info)
279{
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100280 struct m2ua_msg_part *state;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100281 struct m2ua_msg *conf;
Holger Hans Peter Freythere62e4b02011-02-17 23:29:41 +0100282 uint32_t index;
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100283 int req;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100284
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100285 if (link->conn != conn) {
286 LOGP(DINP, LOGL_ERROR,
287 "Someone forgot the ASP Activate on link-index %d\n",
288 link->link_index);
289 return -1;
290 }
291
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100292 state = m2ua_msg_find_tag(m2ua, M2UA_TAG_STATE_REQ);
293 if (!state || state->len != 4) {
294 LOGP(DINP, LOGL_ERROR, "Mandantory state request not present.\n");
295 return -1;
296 }
297
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100298 memcpy(&req, state->dat, 4);
299 req = ntohl(req);
300
301 switch (req) {
302 case M2UA_STATUS_EMER_SET:
303 conf = m2ua_msg_alloc();
304 if (!conf)
305 return -1;
306
Holger Hans Peter Freythere62e4b02011-02-17 23:29:41 +0100307 index = htonl(link->link_index);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100308 conf->hdr.msg_class = M2UA_CLS_MAUP;
309 conf->hdr.msg_type = M2UA_MAUP_STATE_CON;
Holger Hans Peter Freythere62e4b02011-02-17 23:29:41 +0100310 m2ua_msg_add_data(conf, MUA_TAG_IDENT_INT, 4, (uint8_t *) &index);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100311 m2ua_msg_add_data(conf, M2UA_TAG_STATE_REQ, 4, (uint8_t *) &req);
312 if (m2ua_conn_send(conn, conf, info) != 0) {
313 m2ua_msg_free(conf);
314 return -1;
315 }
316 m2ua_msg_free(conf);
Holger Hans Peter Freyther4cee7c02011-02-17 18:41:33 +0100317
318 LOGP(DINP, LOGL_NOTICE, "M2UA link-index %d is running.\n", link->link_index);
319 link->active = 1;
320 mtp_link_up(link->base);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100321 break;
322 default:
323 LOGP(DINP, LOGL_ERROR, "Unknown STATE Request: %d\n", req);
324 break;
325 }
326
327 return 0;
328}
329
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100330static int m2ua_handle_est_req(struct mtp_m2ua_link *link,
331 struct sctp_m2ua_conn *conn,
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100332 struct m2ua_msg *m2ua,
333 struct sctp_sndrcvinfo *info)
334{
Holger Hans Peter Freythere62e4b02011-02-17 23:29:41 +0100335 uint32_t index;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100336 struct m2ua_msg *conf;
337
338 conf = m2ua_msg_alloc();
339 if (!conf)
340 return -1;
341
342 conf->hdr.msg_class = M2UA_CLS_MAUP;
343 conf->hdr.msg_type = M2UA_MAUP_EST_CON;
344
Holger Hans Peter Freythere62e4b02011-02-17 23:29:41 +0100345 index = htonl(link->link_index);
346 m2ua_msg_add_data(conf, MUA_TAG_IDENT_INT, 4, (uint8_t *) &index);
347
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100348 if (m2ua_conn_send(conn, conf, info) != 0) {
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100349 link->established = 0;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100350 m2ua_msg_free(conf);
351 return -1;
352 }
353
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100354 link->established = 1;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100355 m2ua_msg_free(conf);
356 return 0;
357}
358
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100359static int m2ua_handle_rel_req(struct mtp_m2ua_link *link,
360 struct sctp_m2ua_conn *conn,
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100361 struct m2ua_msg *m2ua,
362 struct sctp_sndrcvinfo *info)
363{
Holger Hans Peter Freythere62e4b02011-02-17 23:29:41 +0100364 uint32_t index;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100365 struct m2ua_msg *conf;
366
367 conf = m2ua_msg_alloc();
368 if (!conf)
369 return -1;
370
371 conf->hdr.msg_class = M2UA_CLS_MAUP;
372 conf->hdr.msg_type = M2UA_MAUP_REL_CON;
373
Holger Hans Peter Freythere62e4b02011-02-17 23:29:41 +0100374 index = htonl(link->link_index);
375 m2ua_msg_add_data(conf, MUA_TAG_IDENT_INT, 4, (uint8_t *) &index);
376
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100377 if (m2ua_conn_send(conn, conf, info) != 0) {
378 m2ua_msg_free(conf);
379 return -1;
380 }
381
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100382 link->established = 0;
Holger Hans Peter Freyther4cee7c02011-02-17 18:41:33 +0100383 link->active = 0;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100384 LOGP(DINP, LOGL_NOTICE, "M2UA/Link is released.\n");
Holger Hans Peter Freyther6c0b2e52011-02-17 02:18:38 +0100385 link_down(link->base);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100386 m2ua_msg_free(conf);
387 return 0;
388}
389
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100390static int m2ua_handle_data(struct mtp_m2ua_link *_link,
391 struct sctp_m2ua_conn *conn,
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100392 struct m2ua_msg *m2ua,
393 struct sctp_sndrcvinfo *info)
394{
395 struct msgb *msg;
396 struct m2ua_msg_part *data;
Holger Hans Peter Freytherc17852e2011-01-17 22:23:24 +0100397 struct mtp_link *link;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100398
399 data = m2ua_msg_find_tag(m2ua, M2UA_TAG_DATA);
400 if (!data) {
401 LOGP(DINP, LOGL_ERROR, "No DATA in DATA message.\n");
402 return -1;
403 }
404
405 if (data->len > 2048) {
406 LOGP(DINP, LOGL_ERROR, "TOO much data for us to handle.\n");
407 return -1;
408 }
409
410 msg = msgb_alloc(2048, "m2ua-data");
411 if (!msg) {
412 LOGP(DINP, LOGL_ERROR, "Failed to allocate storage.\n");
413 return -1;
414 }
415
416 msg->l2h = msgb_put(msg, data->len);
417 memcpy(msg->l2h, data->dat, data->len);
Holger Hans Peter Freytherc17852e2011-01-17 22:23:24 +0100418
Holger Hans Peter Freyther6c0b2e52011-02-17 02:18:38 +0100419 link = _link->base;
Holger Hans Peter Freytherea5ce232011-01-23 23:31:26 +0100420 if (!link->blocked) {
421 mtp_handle_pcap(link, NET_IN, msg->l2h, msgb_l2len(msg));
422 mtp_link_set_data(link, msg);
423 }
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100424 msgb_free(msg);
425
426 return 0;
427}
428
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100429static int m2ua_handle_maup(struct mtp_m2ua_link *link,
430 struct sctp_m2ua_conn *conn,
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100431 struct m2ua_msg *m2ua,
432 struct sctp_sndrcvinfo *info)
433{
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100434 if (!link) {
435 LOGP(DINP, LOGL_ERROR, "Link is required.\n");
436 return -1;
437 }
438
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100439 if (link->conn != conn) {
440 LOGP(DINP, LOGL_ERROR,
441 "Someone forgot the ASP Activate on link-index %d\n",
442 link->link_index);
443 return -1;
444 }
445
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100446 switch (m2ua->hdr.msg_type) {
447 case M2UA_MAUP_STATE_REQ:
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100448 m2ua_handle_state_req(link, conn, m2ua, info);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100449 break;
450 case M2UA_MAUP_EST_REQ:
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100451 m2ua_handle_est_req(link, conn, m2ua, info);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100452 break;
453 case M2UA_MAUP_REL_REQ:
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100454 m2ua_handle_rel_req(link, conn, m2ua, info);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100455 break;
456 case M2UA_MAUP_DATA:
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100457 m2ua_handle_data(link, conn, m2ua, info);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100458 break;
459 default:
460 LOGP(DINP, LOGL_ERROR, "Unhandled msg_type %d\n",
461 m2ua->hdr.msg_type);
462 break;
463 }
464
465 return 0;
466}
467
468static int m2ua_handle_mgmt(struct sctp_m2ua_conn *conn,
469 struct m2ua_msg *m2ua, struct sctp_sndrcvinfo *info)
470{
471 switch (m2ua->hdr.msg_type) {
472 case M2UA_MGMT_ERROR:
473 LOGP(DINP, LOGL_ERROR, "We did something wrong. Error...\n");
474 break;
475 case M2UA_MGMT_NTFY:
476 LOGP(DINP, LOGL_NOTICE, "There was a notiy.. but we should only send it.\n");
477 break;
478 }
479
480 return 0;
481}
482
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100483static int m2ua_find_interface(struct m2ua_msg *m2ua, int def)
484{
485 struct m2ua_msg_part *ident;
486
487 ident = m2ua_msg_find_tag(m2ua, MUA_TAG_IDENT_INT);
488 if (ident && ident->len == 4) {
489 memcpy(&def, ident->dat, 4);
490 def = ntohl(def);
491 }
492
493 return def;
494}
495
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100496static int m2ua_conn_handle(struct sctp_m2ua_conn *conn,
497 struct msgb *msg, struct sctp_sndrcvinfo *info)
498{
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100499 struct mtp_m2ua_link *link;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100500 struct m2ua_msg *m2ua;
501 m2ua = m2ua_from_msg(msg->len, msg->data);
502 if (!m2ua) {
503 LOGP(DINP, LOGL_ERROR, "Failed to parse the message.\n");
504 return -1;
505 }
506
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100507 link = find_m2ua_link(conn->trans, m2ua_find_interface(m2ua, 0));
508
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100509 switch (m2ua->hdr.msg_class) {
510 case M2UA_CLS_MGMT:
511 m2ua_handle_mgmt(conn, m2ua, info);
512 break;
513 case M2UA_CLS_ASPSM:
514 m2ua_handle_asp(conn, m2ua, info);
515 break;
516 case M2UA_CLS_ASPTM:
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100517 m2ua_handle_asptm(conn, m2ua, info);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100518 break;
519 case M2UA_CLS_MAUP:
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100520 m2ua_handle_maup(link, conn, m2ua, info);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100521 break;
522 default:
523 LOGP(DINP, LOGL_ERROR, "Unhandled msg_class %d\n",
524 m2ua->hdr.msg_class);
525 break;
526 }
527
528 m2ua_msg_free(m2ua);
529 return 0;
530}
531
532static int m2ua_conn_read(struct bsc_fd *fd)
533{
534 struct sockaddr_in addr;
535 struct sctp_sndrcvinfo info;
536 socklen_t len = sizeof(addr);
537 struct msgb *msg;
538 int rc;
539
540 msg = msgb_alloc(2048, "m2ua buffer");
541 if (!msg) {
542 LOGP(DINP, LOGL_ERROR, "Failed to allocate buffer.\n");
543 m2ua_conn_destroy(fd->data);
544 return -1;
545 }
546
547 memset(&info, 0, sizeof(info));
548 memset(&addr, 0, sizeof(addr));
549 rc = sctp_recvmsg(fd->fd, msg->data, msg->data_len,
550 (struct sockaddr *) &addr, &len, &info, NULL);
Holger Hans Peter Freytherc5562bd2011-01-26 11:02:42 +0100551 if (rc <= 0) {
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100552 LOGP(DINP, LOGL_ERROR, "Failed to read.\n");
553 m2ua_conn_destroy(fd->data);
554 return -1;
555 }
556
557 msgb_put(msg, rc);
Holger Hans Peter Freyther5e5758c2011-02-17 18:18:22 +0100558 LOGP(DINP, LOGL_DEBUG, "Read %d on stream: %d ssn: %d assoc: %d\n",
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100559 rc, info.sinfo_stream, info.sinfo_ssn, info.sinfo_assoc_id);
560 m2ua_conn_handle(fd->data, msg, &info);
561 msgb_free(msg);
562 return 0;
563}
564
565static int sctp_m2ua_write(struct mtp_link *link, struct msgb *msg)
566{
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100567 struct mtp_m2ua_link *mlink;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100568 struct sctp_sndrcvinfo info;
569 struct m2ua_msg *m2ua;
570 uint32_t interface;
571
Holger Hans Peter Freyther6c0b2e52011-02-17 02:18:38 +0100572 mlink = (struct mtp_m2ua_link *) link->data;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100573
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100574
575 if (!mlink->conn) {
576 LOGP(DINP, LOGL_ERROR, "M2UA write with no ASP for %d/%s of %d/%s.\n",
577 link->nr, link->name, link->set->nr, link->set->name);
Holger Hans Peter Freyther1927e632011-02-15 16:51:43 +0100578 goto clean;
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100579 }
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100580
Holger Hans Peter Freyther4cee7c02011-02-17 18:41:33 +0100581 if (!mlink->asp_active || !mlink->established || !mlink->active) {
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100582 LOGP(DINP, LOGL_ERROR, "ASP not ready for %d/%s of %d/%s.\n",
583 link->nr, link->name, link->set->nr, link->set->name);
Holger Hans Peter Freyther1927e632011-02-15 16:51:43 +0100584 goto clean;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100585 }
586
587 m2ua = m2ua_msg_alloc();
588 if (!m2ua)
Holger Hans Peter Freyther1927e632011-02-15 16:51:43 +0100589 goto clean;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100590
Holger Hans Peter Freyther36260e92011-01-22 17:37:56 +0100591 mtp_handle_pcap(link, NET_OUT, msg->data, msg->len);
Holger Hans Peter Freytherc17852e2011-01-17 22:23:24 +0100592
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100593 m2ua->hdr.msg_class = M2UA_CLS_MAUP;
594 m2ua->hdr.msg_type = M2UA_MAUP_DATA;
595
596 interface = htonl(0);
597 m2ua_msg_add_data(m2ua, MUA_TAG_IDENT_INT, 4, (uint8_t *) &interface);
598 m2ua_msg_add_data(m2ua, M2UA_TAG_DATA, msg->len, msg->data);
599
600 memset(&info, 0, sizeof(info));
601 info.sinfo_stream = 1;
602 info.sinfo_assoc_id = 1;
603 info.sinfo_ppid = htonl(2);
604
Holger Hans Peter Freyther8fd28db2011-02-17 14:55:55 +0100605 m2ua_conn_send(mlink->conn, m2ua, &info);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100606 m2ua_msg_free(m2ua);
Holger Hans Peter Freyther1927e632011-02-15 16:51:43 +0100607
608clean:
609 msgb_free(msg);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100610 return 0;
611}
612
613static int m2ua_conn_write(struct bsc_fd *fd, struct msgb *msg)
614{
615 int ret;
616 struct sctp_sndrcvinfo info;
617 memcpy(&info, msg->data, sizeof(info));
618
619 ret = sctp_send(fd->fd, msg->l2h, msgb_l2len(msg),
620 &info, 0);
621
622 if (ret != msgb_l2len(msg))
623 LOGP(DINP, LOGL_ERROR, "Failed to send %d.\n", ret);
624
625 return 0;
626}
627
628static int sctp_trans_accept(struct bsc_fd *fd, unsigned int what)
629{
630 struct sctp_event_subscribe events;
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100631 struct sctp_m2ua_transport *trans;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100632 struct sctp_m2ua_conn *conn;
633 struct sockaddr_in addr;
634 socklen_t len;
635 int s;
636
637 len = sizeof(addr);
638 s = accept(fd->fd, (struct sockaddr *) &addr, &len);
639 if (s < 0) {
640 LOGP(DINP, LOGL_ERROR, "Failed to accept.\n");
641 return -1;
642 }
643
644 trans = fd->data;
645 if (!trans->started) {
646 LOGP(DINP, LOGL_NOTICE, "The link is not started.\n");
647 close(s);
648 return -1;
649 }
650
651 LOGP(DINP, LOGL_NOTICE, "Got a new SCTP connection.\n");
652 conn = talloc_zero(fd->data, struct sctp_m2ua_conn);
653 if (!conn) {
654 LOGP(DINP, LOGL_ERROR, "Failed to create.\n");
655 close(s);
656 return -1;
657 }
658
659 conn->trans = trans;
660
661 write_queue_init(&conn->queue, 10);
662 conn->queue.bfd.fd = s;
663 conn->queue.bfd.data = conn;
664 conn->queue.bfd.when = BSC_FD_READ;
665 conn->queue.read_cb = m2ua_conn_read;
666 conn->queue.write_cb = m2ua_conn_write;
667
668 if (bsc_register_fd(&conn->queue.bfd) != 0) {
669 LOGP(DINP, LOGL_ERROR, "Failed to register.\n");
670 close(s);
671 talloc_free(conn);
672 return -1;
673 }
674
675 memset(&events, 0, sizeof(events));
676 events.sctp_data_io_event = 1;
677 setsockopt(s, SOL_SCTP, SCTP_EVENTS, &events, sizeof(events));
678
679 llist_add_tail(&conn->entry, &trans->conns);
680 return 0;
681}
682
683static int sctp_m2ua_dummy(struct mtp_link *link)
684{
685 return 0;
686}
687
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100688static int sctp_m2ua_start(struct mtp_link *_link)
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100689{
Holger Hans Peter Freyther6c0b2e52011-02-17 02:18:38 +0100690 struct mtp_m2ua_link *link = (struct mtp_m2ua_link *) _link->data;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100691
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100692 link->transport->started = 1;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100693 return 0;
694}
695
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100696static int sctp_m2ua_reset(struct mtp_link *_link)
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100697{
Holger Hans Peter Freyther6c0b2e52011-02-17 02:18:38 +0100698 struct mtp_m2ua_link *link = (struct mtp_m2ua_link *) _link->data;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100699
Holger Hans Peter Freyther7c6feca2011-02-17 15:15:28 +0100700 /*
701 * TODO: Send a Release Indication? Send NTFY to other ASPs to
702 * ask them to activate the link? What should we do here? Right
703 * now do exactly nothing.
704 */
705 LOGP(DINP, LOGL_ERROR,
706 "M2UA link-index %d not doing the reset.\n", link->link_index);
707
708 if (link->conn && link->asp_active && link->established)
709 mtp_link_start_link_test(_link);
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100710
711 return 0;
712}
713
Holger Hans Peter Freyther71760302011-02-22 20:57:08 +0100714struct sctp_m2ua_transport *sctp_m2ua_transp_create(struct bsc_data *bsc)
715{
716 struct sctp_m2ua_transport *trans;
717
718 trans = talloc_zero(bsc, struct sctp_m2ua_transport);
719 if (!trans) {
720 LOGP(DINP, LOGL_ERROR, "Remove the talloc.\n");
721 return NULL;
722 }
723
724 INIT_LLIST_HEAD(&trans->conns);
725 INIT_LLIST_HEAD(&trans->links);
726
727
728 return trans;
729}
730
731int sctp_m2ua_transport_bind(struct sctp_m2ua_transport *trans,
732 const char *ip, int port)
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100733{
734 int sctp;
735 struct sockaddr_in addr;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100736
737 sctp = socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP);
738 if (!sctp) {
739 LOGP(DINP, LOGL_ERROR, "Failed to create socket.\n");
Holger Hans Peter Freyther71760302011-02-22 20:57:08 +0100740 return -1;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100741 }
742
743 memset(&addr, 0, sizeof(addr));
744 addr.sin_family = AF_INET;
745 addr.sin_port = htons(port);
746 addr.sin_addr.s_addr = inet_addr(ip);
747
748 if (bind(sctp, (struct sockaddr *) &addr, sizeof(addr)) != 0) {
749 LOGP(DINP, LOGL_ERROR, "Failed to bind.\n");
750 close(sctp);
Holger Hans Peter Freyther71760302011-02-22 20:57:08 +0100751 return -2;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100752 }
753
754 if (listen(sctp, 1) != 0) {
755 LOGP(DINP, LOGL_ERROR, "Failed to listen.\n");
756 close(sctp);
Holger Hans Peter Freyther71760302011-02-22 20:57:08 +0100757 return -3;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100758 }
759
760 int on = 1;
761 setsockopt(sctp, SOL_SCTP, 112, &on, sizeof(on));
762
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100763 trans->bsc.fd = sctp;
764 trans->bsc.data = trans;
765 trans->bsc.cb = sctp_trans_accept;
766 trans->bsc.when = BSC_FD_READ;
767
768 if (bsc_register_fd(&trans->bsc) != 0) {
769 LOGP(DINP, LOGL_ERROR, "Failed to register the fd.\n");
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100770 close(sctp);
Holger Hans Peter Freyther71760302011-02-22 20:57:08 +0100771 return -4;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100772 }
773
Holger Hans Peter Freyther71760302011-02-22 20:57:08 +0100774 return 0;
Holger Hans Peter Freytherd70a7e82011-01-17 14:13:29 +0100775}
776
Holger Hans Peter Freyther71760302011-02-22 20:57:08 +0100777struct mtp_m2ua_link *mtp_m2ua_link_init(struct mtp_link *blnk)
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100778{
Holger Hans Peter Freyther71760302011-02-22 20:57:08 +0100779 struct sctp_m2ua_transport *trans;
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100780 struct mtp_m2ua_link *lnk;
781
Holger Hans Peter Freyther6c0b2e52011-02-17 02:18:38 +0100782 lnk = talloc_zero(blnk, struct mtp_m2ua_link);
783 if (!lnk) {
784 LOGP(DINP, LOGL_ERROR, "Failed to allocate.\n");
Holger Hans Peter Freyther6c0b2e52011-02-17 02:18:38 +0100785 return NULL;
786 }
787
788 /* make sure we can resolve it both ways */
789 lnk->base = blnk;
790 blnk->data = lnk;
791 blnk->type = SS7_LTYPE_M2UA;
792
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100793 /* remember we have a link here */
Holger Hans Peter Freyther71760302011-02-22 20:57:08 +0100794 trans = blnk->set->bsc->m2ua_trans;
Holger Hans Peter Freyther169a1a92011-02-22 15:45:52 +0100795 llist_add_tail(&lnk->entry, &trans->links);
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100796
Holger Hans Peter Freyther6c0b2e52011-02-17 02:18:38 +0100797 lnk->base->shutdown = sctp_m2ua_reset;
798 lnk->base->clear_queue = sctp_m2ua_dummy;
799 lnk->base->reset = sctp_m2ua_reset;
800 lnk->base->start = sctp_m2ua_start;
801 lnk->base->write = sctp_m2ua_write;
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100802
Holger Hans Peter Freytherb27c9622011-02-16 23:47:25 +0100803 lnk->transport = trans;
Holger Hans Peter Freytherf7ce2c62011-02-15 15:45:32 +0100804 return lnk;
805}