aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <zecke@selfish.org>2011-02-15 15:45:32 +0100
committerHolger Hans Peter Freyther <zecke@selfish.org>2011-02-17 19:34:27 +0100
commitf7ce2c6417b2cda3b0672d84f1ac9085c6f86f3a (patch)
treeeb69cf14594fb69d4604961eecfcc79a6a83173c
parent694337f8939aadeff60d931f827184f6c37f1926 (diff)
m2ua: Start to separate the SCTP code and M2UA to allow multiple links
We want to be able to support multiple links over different SCTP connection and in the future also over the same connection. This is the first step to separate the SCTP connection handling from the link handling inside these messages.
-rw-r--r--include/bsc_data.h4
-rw-r--r--include/sctp_m2ua.h19
-rw-r--r--src/main_stp.c8
-rw-r--r--src/sctp_m2ua.c171
4 files changed, 141 insertions, 61 deletions
diff --git a/include/bsc_data.h b/include/bsc_data.h
index df62493..6fb5b26 100644
--- a/include/bsc_data.h
+++ b/include/bsc_data.h
@@ -39,6 +39,7 @@
struct bsc_data;
struct snmp_mtp_session;
+struct mtp_m2ua_transport;
/**
* Struct holding the BSC to MSC forwarding state.
@@ -155,6 +156,9 @@ struct bsc_data {
/* MSC related data... currently only one is supported */
struct bsc_msc_forward msc_forward;
+
+ /* m2ua code */
+ struct sctp_m2ua_transport *m2ua_trans;
};
/* bsc related functions */
diff --git a/include/sctp_m2ua.h b/include/sctp_m2ua.h
index 2627d7d..dcb6269 100644
--- a/include/sctp_m2ua.h
+++ b/include/sctp_m2ua.h
@@ -33,12 +33,20 @@ struct mtp_link;
* Drive M2UA over a SCTP link. Right now we have no
* real concept for failover and such for the link.
*/
-struct mtp_m2ua_link {
- struct mtp_link base;
-
+struct sctp_m2ua_transport {
int started;
struct llist_head conns;
struct bsc_fd bsc;
+
+ struct llist_head links;
+};
+
+struct mtp_m2ua_link {
+ struct mtp_link base;
+
+ int link_index;
+ struct llist_head entry;
+ struct sctp_m2ua_transport *transport;
};
/*
@@ -52,9 +60,10 @@ struct sctp_m2ua_conn {
int established;
struct write_queue queue;
- struct mtp_m2ua_link *trans;
+ struct sctp_m2ua_transport *trans;
};
-struct mtp_m2ua_link *sctp_m2ua_transp_create(const char *ip, int port);
+struct sctp_m2ua_transport *sctp_m2ua_transp_create(const char *ip, int port);
+struct mtp_m2ua_link *mtp_m2ua_link_create(struct mtp_link_set *);
#endif
diff --git a/src/main_stp.c b/src/main_stp.c
index a26823d..203ce12 100644
--- a/src/main_stp.c
+++ b/src/main_stp.c
@@ -356,6 +356,12 @@ int main(int argc, char **argv)
if (!set)
return -1;
+ bsc->m2ua_trans = sctp_m2ua_transp_create("0.0.0.0", 2904);
+ if (!bsc->m2ua_trans) {
+ LOGP(DINP, LOGL_ERROR, "Failed to create SCTP transport.\n");
+ return -1;
+ }
+
m2ua_set = mtp_link_set_alloc(bsc);
m2ua_set->dpc = 92;
m2ua_set->opc = 9;
@@ -372,7 +378,7 @@ int main(int argc, char **argv)
m2ua_set->pass_all_isup = bsc->isup_pass;
m2ua_set->forward = set;
- lnk = sctp_m2ua_transp_create("0.0.0.0", 2904);
+ lnk = mtp_m2ua_link_create(m2ua_set);
lnk->base.pcap_fd = -1;
mtp_link_set_add_link(m2ua_set, (struct mtp_link *) lnk);
diff --git a/src/sctp_m2ua.c b/src/sctp_m2ua.c
index 2b8ac07..0e0c083 100644
--- a/src/sctp_m2ua.c
+++ b/src/sctp_m2ua.c
@@ -30,6 +30,19 @@
#include <string.h>
#include <unistd.h>
+static struct mtp_m2ua_link *find_m2ua_link(struct sctp_m2ua_transport *trans, int link_index)
+{
+ struct mtp_m2ua_link *link;
+ link_index = link_index;
+
+ llist_for_each_entry(link, &trans->links, entry) {
+ if (link->link_index == link_index)
+ return link;
+ }
+
+ return NULL;
+}
+
static void link_down(struct mtp_link *link)
{
rate_ctr_inc(&link->ctrg->ctr[MTP_LNK_ERROR]);
@@ -38,13 +51,17 @@ static void link_down(struct mtp_link *link)
static void m2ua_conn_destroy(struct sctp_m2ua_conn *conn)
{
+ struct mtp_m2ua_link *link;
+
close(conn->queue.bfd.fd);
bsc_unregister_fd(&conn->queue.bfd);
write_queue_clear(&conn->queue);
llist_del(&conn->entry);
- if (conn->asp_up && conn->asp_active && conn->established)
- link_down(&conn->trans->base);
+ /* TODO: hardcoded link index */
+ link = find_m2ua_link(conn->trans, 0);
+ if (link && conn->asp_up && conn->asp_active && conn->established)
+ link_down(&link->base);
talloc_free(conn);
#warning "Notify any other AS(P) for failover scenario"
@@ -73,7 +90,8 @@ static int m2ua_conn_send(struct sctp_m2ua_conn *conn,
return 0;
}
-static int m2ua_conn_send_ntfy(struct sctp_m2ua_conn *conn,
+static int m2ua_conn_send_ntfy(struct mtp_m2ua_link *link,
+ struct sctp_m2ua_conn *conn,
struct sctp_sndrcvinfo *info)
{
struct m2ua_msg *msg;
@@ -94,6 +112,8 @@ static int m2ua_conn_send_ntfy(struct sctp_m2ua_conn *conn,
else
state[1] = ntohs(M2UA_STP_AS_INACTIVE);
+ /* TODO: embed the interface identifier */
+
m2ua_msg_add_data(msg, MUA_TAG_STATUS, 4, (uint8_t *) state);
m2ua_msg_add_data(msg, MUA_TAG_ASP_IDENT, 4, conn->asp_ident);
rc = m2ua_conn_send(conn, msg, info);
@@ -136,7 +156,6 @@ static int m2ua_handle_asp_ack(struct sctp_m2ua_conn *conn,
memcpy(conn->asp_ident, asp_ident->dat, 4);
conn->asp_up = 1;
- m2ua_conn_send_ntfy(conn, info);
m2ua_msg_free(ack);
return 0;
}
@@ -157,7 +176,8 @@ static int m2ua_handle_asp(struct sctp_m2ua_conn *conn,
return 0;
}
-static int m2ua_handle_asptm_act(struct sctp_m2ua_conn *conn,
+static int m2ua_handle_asptm_act(struct mtp_m2ua_link *link,
+ struct sctp_m2ua_conn *conn,
struct m2ua_msg *m2ua,
struct sctp_sndrcvinfo *info)
{
@@ -177,18 +197,24 @@ static int m2ua_handle_asptm_act(struct sctp_m2ua_conn *conn,
}
conn->asp_active = 1;
- m2ua_conn_send_ntfy(conn, info);
+ m2ua_conn_send_ntfy(link, conn, info);
m2ua_msg_free(ack);
return 0;
}
-static int m2ua_handle_asptm(struct sctp_m2ua_conn *conn,
+static int m2ua_handle_asptm(struct mtp_m2ua_link *link,
+ struct sctp_m2ua_conn *conn,
struct m2ua_msg *m2ua,
struct sctp_sndrcvinfo *info)
{
+ if (!link) {
+ LOGP(DINP, LOGL_ERROR, "Link is required.\n");
+ return -1;
+ }
+
switch (m2ua->hdr.msg_type) {
case M2UA_ASPTM_ACTIV:
- m2ua_handle_asptm_act(conn, m2ua, info);
+ m2ua_handle_asptm_act(link, conn, m2ua, info);
break;
default:
LOGP(DINP, LOGL_ERROR, "Unhandled msg_type %d\n",
@@ -199,13 +225,14 @@ static int m2ua_handle_asptm(struct sctp_m2ua_conn *conn,
return 0;
}
-static int m2ua_handle_state_req(struct sctp_m2ua_conn *conn,
+static int m2ua_handle_state_req(struct mtp_m2ua_link *link,
+ struct sctp_m2ua_conn *conn,
struct m2ua_msg *m2ua,
struct sctp_sndrcvinfo *info)
{
- struct m2ua_msg_part *ident, *state;
+ struct m2ua_msg_part *state;
struct m2ua_msg *conf;
- int interface = 0, req;
+ int req;
state = m2ua_msg_find_tag(m2ua, M2UA_TAG_STATE_REQ);
if (!state || state->len != 4) {
@@ -213,12 +240,6 @@ static int m2ua_handle_state_req(struct sctp_m2ua_conn *conn,
return -1;
}
- ident = m2ua_msg_find_tag(m2ua, MUA_TAG_IDENT_INT);
- if (ident && ident->len == 4) {
- memcpy(&interface, ident->dat, 4);
- interface = ntohl(interface);
- }
-
memcpy(&req, state->dat, 4);
req = ntohl(req);
@@ -230,7 +251,7 @@ static int m2ua_handle_state_req(struct sctp_m2ua_conn *conn,
conf->hdr.msg_class = M2UA_CLS_MAUP;
conf->hdr.msg_type = M2UA_MAUP_STATE_CON;
- m2ua_msg_add_data(conf, MUA_TAG_IDENT_INT, 4, (uint8_t *) &interface);
+ m2ua_msg_add_data(conf, MUA_TAG_IDENT_INT, 4, (uint8_t *) &link->link_index);
m2ua_msg_add_data(conf, M2UA_TAG_STATE_REQ, 4, (uint8_t *) &req);
if (m2ua_conn_send(conn, conf, info) != 0) {
m2ua_msg_free(conf);
@@ -246,7 +267,8 @@ static int m2ua_handle_state_req(struct sctp_m2ua_conn *conn,
return 0;
}
-static int m2ua_handle_est_req(struct sctp_m2ua_conn *conn,
+static int m2ua_handle_est_req(struct mtp_m2ua_link *link,
+ struct sctp_m2ua_conn *conn,
struct m2ua_msg *m2ua,
struct sctp_sndrcvinfo *info)
{
@@ -266,12 +288,13 @@ static int m2ua_handle_est_req(struct sctp_m2ua_conn *conn,
conn->established = 1;
LOGP(DINP, LOGL_NOTICE, "M2UA/Link is established.\n");
- mtp_link_up(&conn->trans->base);
+ mtp_link_up(&link->base);
m2ua_msg_free(conf);
return 0;
}
-static int m2ua_handle_rel_req(struct sctp_m2ua_conn *conn,
+static int m2ua_handle_rel_req(struct mtp_m2ua_link *link,
+ struct sctp_m2ua_conn *conn,
struct m2ua_msg *m2ua,
struct sctp_sndrcvinfo *info)
{
@@ -291,12 +314,13 @@ static int m2ua_handle_rel_req(struct sctp_m2ua_conn *conn,
conn->established = 0;
LOGP(DINP, LOGL_NOTICE, "M2UA/Link is released.\n");
- link_down(&conn->trans->base);
+ link_down(&link->base);
m2ua_msg_free(conf);
return 0;
}
-static int m2ua_handle_data(struct sctp_m2ua_conn *conn,
+static int m2ua_handle_data(struct mtp_m2ua_link *_link,
+ struct sctp_m2ua_conn *conn,
struct m2ua_msg *m2ua,
struct sctp_sndrcvinfo *info)
{
@@ -324,7 +348,7 @@ static int m2ua_handle_data(struct sctp_m2ua_conn *conn,
msg->l2h = msgb_put(msg, data->len);
memcpy(msg->l2h, data->dat, data->len);
- link = &conn->trans->base;
+ link = &_link->base;
if (!link->blocked) {
mtp_handle_pcap(link, NET_IN, msg->l2h, msgb_l2len(msg));
mtp_link_set_data(link, msg);
@@ -334,22 +358,28 @@ static int m2ua_handle_data(struct sctp_m2ua_conn *conn,
return 0;
}
-static int m2ua_handle_maup(struct sctp_m2ua_conn *conn,
+static int m2ua_handle_maup(struct mtp_m2ua_link *link,
+ struct sctp_m2ua_conn *conn,
struct m2ua_msg *m2ua,
struct sctp_sndrcvinfo *info)
{
+ if (!link) {
+ LOGP(DINP, LOGL_ERROR, "Link is required.\n");
+ return -1;
+ }
+
switch (m2ua->hdr.msg_type) {
case M2UA_MAUP_STATE_REQ:
- m2ua_handle_state_req(conn, m2ua, info);
+ m2ua_handle_state_req(link, conn, m2ua, info);
break;
case M2UA_MAUP_EST_REQ:
- m2ua_handle_est_req(conn, m2ua, info);
+ m2ua_handle_est_req(link, conn, m2ua, info);
break;
case M2UA_MAUP_REL_REQ:
- m2ua_handle_rel_req(conn, m2ua, info);
+ m2ua_handle_rel_req(link, conn, m2ua, info);
break;
case M2UA_MAUP_DATA:
- m2ua_handle_data(conn, m2ua, info);
+ m2ua_handle_data(link, conn, m2ua, info);
break;
default:
LOGP(DINP, LOGL_ERROR, "Unhandled msg_type %d\n",
@@ -375,9 +405,23 @@ static int m2ua_handle_mgmt(struct sctp_m2ua_conn *conn,
return 0;
}
+static int m2ua_find_interface(struct m2ua_msg *m2ua, int def)
+{
+ struct m2ua_msg_part *ident;
+
+ ident = m2ua_msg_find_tag(m2ua, MUA_TAG_IDENT_INT);
+ if (ident && ident->len == 4) {
+ memcpy(&def, ident->dat, 4);
+ def = ntohl(def);
+ }
+
+ return def;
+}
+
static int m2ua_conn_handle(struct sctp_m2ua_conn *conn,
struct msgb *msg, struct sctp_sndrcvinfo *info)
{
+ struct mtp_m2ua_link *link;
struct m2ua_msg *m2ua;
m2ua = m2ua_from_msg(msg->len, msg->data);
if (!m2ua) {
@@ -385,6 +429,8 @@ static int m2ua_conn_handle(struct sctp_m2ua_conn *conn,
return -1;
}
+ link = find_m2ua_link(conn->trans, m2ua_find_interface(m2ua, 0));
+
switch (m2ua->hdr.msg_class) {
case M2UA_CLS_MGMT:
m2ua_handle_mgmt(conn, m2ua, info);
@@ -393,10 +439,10 @@ static int m2ua_conn_handle(struct sctp_m2ua_conn *conn,
m2ua_handle_asp(conn, m2ua, info);
break;
case M2UA_CLS_ASPTM:
- m2ua_handle_asptm(conn, m2ua, info);
+ m2ua_handle_asptm(link, conn, m2ua, info);
break;
case M2UA_CLS_MAUP:
- m2ua_handle_maup(conn, m2ua, info);
+ m2ua_handle_maup(link, conn, m2ua, info);
break;
default:
LOGP(DINP, LOGL_ERROR, "Unhandled msg_class %d\n",
@@ -443,13 +489,15 @@ static int m2ua_conn_read(struct bsc_fd *fd)
static int sctp_m2ua_write(struct mtp_link *link, struct msgb *msg)
{
- struct mtp_m2ua_link *trans;
+ struct mtp_m2ua_link *mlink;
+ struct sctp_m2ua_transport *trans;
struct sctp_m2ua_conn *conn = NULL, *tmp;
struct sctp_sndrcvinfo info;
struct m2ua_msg *m2ua;
uint32_t interface;
- trans = (struct mtp_m2ua_link *) link;
+ mlink = (struct mtp_m2ua_link *) link;
+ trans = mlink->transport;
if (llist_empty(&trans->conns))
goto clean;
@@ -509,7 +557,7 @@ static int m2ua_conn_write(struct bsc_fd *fd, struct msgb *msg)
static int sctp_trans_accept(struct bsc_fd *fd, unsigned int what)
{
struct sctp_event_subscribe events;
- struct mtp_m2ua_link *trans;
+ struct sctp_m2ua_transport *trans;
struct sctp_m2ua_conn *conn;
struct sockaddr_in addr;
socklen_t len;
@@ -529,12 +577,6 @@ static int sctp_trans_accept(struct bsc_fd *fd, unsigned int what)
return -1;
}
- if (trans->base.blocked) {
- LOGP(DINP, LOGL_NOTICE, "The link is blocked.\n");
- close(s);
- return -1;
- }
-
LOGP(DINP, LOGL_NOTICE, "Got a new SCTP connection.\n");
conn = talloc_zero(fd->data, struct sctp_m2ua_conn);
if (!conn) {
@@ -572,30 +614,31 @@ static int sctp_m2ua_dummy(struct mtp_link *link)
return 0;
}
-static int sctp_m2ua_start(struct mtp_link *link)
+static int sctp_m2ua_start(struct mtp_link *_link)
{
- struct mtp_m2ua_link *trans = (struct mtp_m2ua_link *) link;
+ struct mtp_m2ua_link *link = (struct mtp_m2ua_link *) _link;
- trans->started = 1;
+ link->transport->started = 1;
return 0;
}
-static int sctp_m2ua_reset(struct mtp_link *link)
+static int sctp_m2ua_reset(struct mtp_link *_link)
{
struct sctp_m2ua_conn *conn, *tmp;
- struct mtp_m2ua_link *transp = (struct mtp_m2ua_link *) link;
+ struct mtp_m2ua_link *link = (struct mtp_m2ua_link *) _link;
- llist_for_each_entry_safe(conn, tmp, &transp->conns, entry)
+ /* TODO: only connection that use the current link index! */
+ llist_for_each_entry_safe(conn, tmp, &link->transport->conns, entry)
m2ua_conn_destroy(conn);
return 0;
}
-struct mtp_m2ua_link *sctp_m2ua_transp_create(const char *ip, int port)
+struct sctp_m2ua_transport *sctp_m2ua_transp_create(const char *ip, int port)
{
int sctp;
struct sockaddr_in addr;
- struct mtp_m2ua_link *trans;
+ struct sctp_m2ua_transport *trans;
sctp = socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP);
if (!sctp) {
@@ -623,19 +666,13 @@ struct mtp_m2ua_link *sctp_m2ua_transp_create(const char *ip, int port)
int on = 1;
setsockopt(sctp, SOL_SCTP, 112, &on, sizeof(on));
- trans = talloc_zero(NULL, struct mtp_m2ua_link);
+ trans = talloc_zero(NULL, struct sctp_m2ua_transport);
if (!trans) {
LOGP(DINP, LOGL_ERROR, "Remove the talloc.\n");
close(sctp);
return NULL;
}
- trans->base.shutdown = sctp_m2ua_reset;
- trans->base.clear_queue = sctp_m2ua_dummy;
- trans->base.reset = sctp_m2ua_reset;
- trans->base.start = sctp_m2ua_start;
- trans->base.write = sctp_m2ua_write;
-
trans->bsc.fd = sctp;
trans->bsc.data = trans;
trans->bsc.cb = sctp_trans_accept;
@@ -649,6 +686,30 @@ struct mtp_m2ua_link *sctp_m2ua_transp_create(const char *ip, int port)
}
INIT_LLIST_HEAD(&trans->conns);
+ INIT_LLIST_HEAD(&trans->links);
+
return trans;
}
+struct mtp_m2ua_link *mtp_m2ua_link_create(struct mtp_link_set *set)
+{
+ struct mtp_m2ua_link *lnk;
+
+ lnk = talloc_zero(set, struct mtp_m2ua_link);
+ if (!lnk) {
+ LOGP(DINP, LOGL_ERROR, "Failed to allocate.\n");
+ return NULL;
+ }
+
+ /* remember we have a link here */
+ llist_add(&lnk->entry, &set->bsc->m2ua_trans->links);
+
+ lnk->base.shutdown = sctp_m2ua_reset;
+ lnk->base.clear_queue = sctp_m2ua_dummy;
+ lnk->base.reset = sctp_m2ua_reset;
+ lnk->base.start = sctp_m2ua_start;
+ lnk->base.write = sctp_m2ua_write;
+
+ lnk->transport = set->bsc->m2ua_trans;
+ return lnk;
+}