summaryrefslogtreecommitdiffstats
path: root/openbsc
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <zecke@selfish.org>2010-01-27 12:25:13 +0100
committerHolger Hans Peter Freyther <zecke@selfish.org>2010-01-27 12:31:50 +0100
commit71c7bf590705be53056793e58e0cceff9ff5d9df (patch)
tree9874ce800b3d8215cddf62072a2160fba5c5271f /openbsc
parent869033148cad1ade6f1bf92320d3ea6ffb3609fe (diff)
[sccp] Separate connection parsing and policy for connection request
The same concept as with the previous patch, make the reject method work on the source local reference instead of passing it the header.
Diffstat (limited to 'openbsc')
-rw-r--r--openbsc/src/sccp/sccp.c108
1 files changed, 60 insertions, 48 deletions
diff --git a/openbsc/src/sccp/sccp.c b/openbsc/src/sccp/sccp.c
index 4c59acc04..2d43aac26 100644
--- a/openbsc/src/sccp/sccp.c
+++ b/openbsc/src/sccp/sccp.c
@@ -199,9 +199,54 @@ static int _sccp_parse_optional_data(const int offset,
return -1;
}
-int _sccp_parse_connection_request(struct msgb *msg, struct sccp_parse_result *result)
+int _sccp_parse_connection_request(struct msgb *msgb, struct sccp_parse_result *result)
{
- return -1;
+ static const u_int32_t header_size =
+ sizeof(struct sccp_connection_request);
+ static const u_int32_t optional_offset =
+ offsetof(struct sccp_connection_request, optional_start);
+ static const u_int32_t called_offset =
+ offsetof(struct sccp_connection_request, variable_called);
+
+ struct sccp_connection_request *req = (struct sccp_connection_request *)msgb->data;
+ struct sccp_optional_data optional_data;
+
+ /* header check */
+ if (msgb_l2len(msgb) < header_size) {
+ DEBUGP(DSCCP, "msgb < header_size %u %u\n",
+ msgb_l2len(msgb), header_size);
+ return -1;
+ }
+
+ /* copy out the calling and called address. Add the offset */
+ if (copy_address(&result->called, called_offset + req->variable_called, msgb) != 0)
+ return -1;
+
+ if (check_address(&result->called) != 0) {
+ DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n",
+ *(u_int8_t *)&result->called.address, result->called.ssn);
+ return -1;
+ }
+
+ result->source_local_reference = &req->source_local_reference;
+
+ /*
+ * parse optional data.
+ */
+ memset(&optional_data, 0, sizeof(optional_data));
+ if (_sccp_parse_optional_data(optional_offset + req->optional_start, msgb, &optional_data) != 0) {
+ DEBUGP(DSCCP, "parsing of optional data failed.\n");
+ return -1;
+ }
+
+ if (optional_data.data_len != 0) {
+ msgb->l3h = &msgb->l2h[optional_data.data_start];
+ result->data_len = optional_data.data_len;
+ } else {
+ result->data_len = 0;
+ }
+
+ return 0;
}
int _sccp_parse_connection_released(struct msgb *msg, struct sccp_parse_result *result)
@@ -413,7 +458,7 @@ static void _sccp_set_connection_state(struct sccp_connection *connection, int n
connection->state_cb(connection, old_state);
}
-static int _sccp_send_refuse(struct sccp_connection_request *req, int cause)
+static int _sccp_send_refuse(struct sccp_source_reference *src_ref, int cause)
{
struct msgb *msgb;
struct sccp_connection_refused *ref;
@@ -426,7 +471,7 @@ static int _sccp_send_refuse(struct sccp_connection_request *req, int cause)
ref = (struct sccp_connection_refused *) msgb_put(msgb, sizeof(*ref));
ref->type = SCCP_MSG_TYPE_CREF;
- memcpy(&ref->destination_local_reference, &req->source_local_reference,
+ memcpy(&ref->destination_local_reference, src_ref,
sizeof(struct sccp_source_reference));
ref->cause = cause;
ref->optional_start = 1;
@@ -640,39 +685,17 @@ static int _sccp_send_connection_released(struct sccp_connection *conn, int caus
*/
static int _sccp_handle_connection_request(struct msgb *msgb)
{
- static const u_int32_t header_size =
- sizeof(struct sccp_connection_request);
- static const u_int32_t optional_offset =
- offsetof(struct sccp_connection_request, optional_start);
- static const u_int32_t called_offset =
- offsetof(struct sccp_connection_request, variable_called);
+ struct sccp_parse_result result;
struct sccp_data_callback *cb;
- struct sccp_connection_request *req = (struct sccp_connection_request *)msgb->data;
- struct sccp_address called;
struct sccp_connection *connection;
- struct sccp_optional_data optional_data;
- /* header check */
- if (msgb_l2len(msgb) < header_size) {
- DEBUGP(DSCCP, "msgb < header_size %u %u\n",
- msgb_l2len(msgb), header_size);
+ if (_sccp_parse_connection_request(msgb, &result) != 0)
return -1;
- }
- /* copy out the calling and called address. Add the offset */
- if (copy_address(&called, called_offset + req->variable_called, msgb) != 0)
- return -1;
-
- if (check_address(&called) != 0) {
- DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n",
- *(u_int8_t *)&called.address, called.ssn);
- return -1;
- }
-
- cb = _find_ssn(called.ssn);
+ cb = _find_ssn(result.called.ssn);
if (!cb || !cb->accept_cb) {
- DEBUGP(DSCCP, "No routing for CR for called SSN: %u\n", called.ssn);
+ DEBUGP(DSCCP, "No routing for CR for called SSN: %u\n", result.called.ssn);
return -1;
}
@@ -690,28 +713,18 @@ static int _sccp_handle_connection_request(struct msgb *msgb)
* and send a connection confirm, otherwise we will send a refuseed
* one....
*/
- if (destination_local_reference_is_free(&req->source_local_reference) != 0) {
+ if (destination_local_reference_is_free(result.source_local_reference) != 0) {
DEBUGP(DSCCP, "Need to reject connection with existing reference\n");
- _sccp_send_refuse(req, SCCP_REFUSAL_SCCP_FAILURE);
+ _sccp_send_refuse(result.source_local_reference, SCCP_REFUSAL_SCCP_FAILURE);
talloc_free(connection);
return -1;
}
connection->incoming = 1;
- connection->destination_local_reference = req->source_local_reference;
-
- /*
- * parse optional data.
- */
- memset(&optional_data, 0, sizeof(optional_data));
- if (_sccp_parse_optional_data(optional_offset + req->optional_start, msgb, &optional_data) != 0) {
- DEBUGP(DSCCP, "parsing of optional data failed.\n");
- talloc_free(connection);
- return -1;
- }
+ connection->destination_local_reference = *result.source_local_reference;
if (cb->accept_cb(connection, cb->accept_context) != 0) {
- _sccp_send_refuse(req, SCCP_REFUSAL_END_USER_ORIGINATED);
+ _sccp_send_refuse(result.source_local_reference, SCCP_REFUSAL_END_USER_ORIGINATED);
_sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_REFUSED);
talloc_free(connection);
return 0;
@@ -723,7 +736,7 @@ static int _sccp_handle_connection_request(struct msgb *msgb)
if (_sccp_send_connection_confirm(connection) != 0) {
DEBUGP(DSCCP, "Sending confirm failed... no available source reference?\n");
- _sccp_send_refuse(req, SCCP_REFUSAL_SCCP_FAILURE);
+ _sccp_send_refuse(result.source_local_reference, SCCP_REFUSAL_SCCP_FAILURE);
_sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_REFUSED);
llist_del(&connection->list);
talloc_free(connection);
@@ -734,9 +747,8 @@ static int _sccp_handle_connection_request(struct msgb *msgb)
/*
* If we have data let us forward things.
*/
- if (optional_data.data_len != 0 && connection->data_cb) {
- msgb->l3h = &msgb->l2h[optional_data.data_start];
- connection->data_cb(connection, msgb, optional_data.data_len);
+ if (result.data_len != 0 && connection->data_cb) {
+ connection->data_cb(connection, msgb, result.data_len);
}
return 0;