Merge branch 'on-waves/sccp'
This commit is contained in:
commit
7184c2d7d2
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* SCCP management code
|
* SCCP management code
|
||||||
*
|
*
|
||||||
* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
|
* (C) 2009, 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||||
*
|
*
|
||||||
* All Rights Reserved
|
* All Rights Reserved
|
||||||
*
|
*
|
||||||
|
@ -143,4 +143,25 @@ extern const struct sockaddr_sccp sccp_ssn_bssap;
|
||||||
u_int32_t sccp_src_ref_to_int(struct sccp_source_reference *ref);
|
u_int32_t sccp_src_ref_to_int(struct sccp_source_reference *ref);
|
||||||
struct sccp_source_reference sccp_src_ref_from_int(u_int32_t);
|
struct sccp_source_reference sccp_src_ref_from_int(u_int32_t);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Below this are helper functions and structs for parsing SCCP messages
|
||||||
|
*/
|
||||||
|
struct sccp_parse_result {
|
||||||
|
struct sccp_address called;
|
||||||
|
struct sccp_address calling;
|
||||||
|
|
||||||
|
/* point to the msg packet */
|
||||||
|
struct sccp_source_reference *source_local_reference;
|
||||||
|
struct sccp_source_reference *destination_local_reference;
|
||||||
|
|
||||||
|
/* data pointer */
|
||||||
|
int data_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* helper functions for the nat code
|
||||||
|
*/
|
||||||
|
int sccp_determine_msg_type(struct msgb *msg);
|
||||||
|
int sccp_parse_header(struct msgb *msg, struct sccp_parse_result *result);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
/*
|
/*
|
||||||
* SCCP management code
|
* SCCP management code
|
||||||
*
|
*
|
||||||
* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
|
* (C) 2009, 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||||
* (C) 2009 by on-waves.com
|
* (C) 2009, 2010 by On-Waves
|
||||||
*
|
*
|
||||||
* All Rights Reserved
|
* All Rights Reserved
|
||||||
*
|
*
|
||||||
|
@ -200,6 +200,277 @@ static int _sccp_parse_optional_data(const int offset,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int _sccp_parse_connection_request(struct msgb *msgb, struct sccp_parse_result *result)
|
||||||
|
{
|
||||||
|
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 *msgb, struct sccp_parse_result *result)
|
||||||
|
{
|
||||||
|
static int header_size = sizeof(struct sccp_connection_released);
|
||||||
|
static int optional_offset = offsetof(struct sccp_connection_released, optional_start);
|
||||||
|
|
||||||
|
struct sccp_optional_data optional_data;
|
||||||
|
struct sccp_connection_released *rls = (struct sccp_connection_released *) msgb->l2h;
|
||||||
|
|
||||||
|
/* we don't have enough size for the struct */
|
||||||
|
if (msgb_l2len(msgb) < header_size) {
|
||||||
|
DEBUGP(DSCCP, "msgb > header_size %u %u\n",
|
||||||
|
msgb_l2len(msgb), header_size);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&optional_data, 0, sizeof(optional_data));
|
||||||
|
if (_sccp_parse_optional_data(optional_offset + rls->optional_start, msgb, &optional_data) != 0) {
|
||||||
|
DEBUGP(DSCCP, "parsing of optional data failed.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
result->source_local_reference = &rls->source_local_reference;
|
||||||
|
result->destination_local_reference = &rls->destination_local_reference;
|
||||||
|
|
||||||
|
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_refused(struct msgb *msgb, struct sccp_parse_result *result)
|
||||||
|
{
|
||||||
|
static const u_int32_t header_size =
|
||||||
|
sizeof(struct sccp_connection_refused);
|
||||||
|
static int optional_offset = offsetof(struct sccp_connection_refused, optional_start);
|
||||||
|
|
||||||
|
struct sccp_optional_data optional_data;
|
||||||
|
struct sccp_connection_refused *ref;
|
||||||
|
|
||||||
|
/* header check */
|
||||||
|
if (msgb_l2len(msgb) < header_size) {
|
||||||
|
DEBUGP(DSCCP, "msgb < header_size %u %u\n",
|
||||||
|
msgb_l2len(msgb), header_size);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ref = (struct sccp_connection_refused *) msgb->l2h;
|
||||||
|
|
||||||
|
result->destination_local_reference = &ref->destination_local_reference;
|
||||||
|
|
||||||
|
memset(&optional_data, 0, sizeof(optional_data));
|
||||||
|
if (_sccp_parse_optional_data(optional_offset + ref->optional_start, msgb, &optional_data) != 0) {
|
||||||
|
DEBUGP(DSCCP, "parsing of optional data failed.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* optional data */
|
||||||
|
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_confirm(struct msgb *msgb, struct sccp_parse_result *result)
|
||||||
|
{
|
||||||
|
static u_int32_t header_size =
|
||||||
|
sizeof(struct sccp_connection_confirm);
|
||||||
|
static const u_int32_t optional_offset =
|
||||||
|
offsetof(struct sccp_connection_confirm, optional_start);
|
||||||
|
|
||||||
|
struct sccp_optional_data optional_data;
|
||||||
|
struct sccp_connection_confirm *con;
|
||||||
|
|
||||||
|
/* header check */
|
||||||
|
if (msgb_l2len(msgb) < header_size) {
|
||||||
|
DEBUGP(DSCCP, "msgb < header_size %u %u\n",
|
||||||
|
msgb_l2len(msgb), header_size);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
con = (struct sccp_connection_confirm *) msgb->l2h;
|
||||||
|
result->destination_local_reference = &con->destination_local_reference;
|
||||||
|
result->source_local_reference = &con->source_local_reference;
|
||||||
|
|
||||||
|
memset(&optional_data, 0, sizeof(optional_data));
|
||||||
|
if (_sccp_parse_optional_data(optional_offset + con->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_release_complete(struct msgb *msgb, struct sccp_parse_result *result)
|
||||||
|
{
|
||||||
|
static int header_size = sizeof(struct sccp_connection_release_complete);
|
||||||
|
|
||||||
|
struct sccp_connection_release_complete *cmpl;
|
||||||
|
|
||||||
|
/* header check */
|
||||||
|
if (msgb_l2len(msgb) < header_size) {
|
||||||
|
DEBUGP(DSCCP, "msgb < header_size %u %u\n",
|
||||||
|
msgb_l2len(msgb), header_size);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmpl = (struct sccp_connection_release_complete *) msgb->l2h;
|
||||||
|
result->source_local_reference = &cmpl->source_local_reference;
|
||||||
|
result->destination_local_reference = &cmpl->destination_local_reference;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _sccp_parse_connection_dt1(struct msgb *msgb, struct sccp_parse_result *result)
|
||||||
|
{
|
||||||
|
static int header_size = sizeof(struct sccp_data_form1);
|
||||||
|
static int variable_offset = offsetof(struct sccp_data_form1, variable_start);
|
||||||
|
|
||||||
|
struct sccp_data_form1 *dt1 = (struct sccp_data_form1 *)msgb->l2h;
|
||||||
|
|
||||||
|
/* we don't have enough size for the struct */
|
||||||
|
if (msgb_l2len(msgb) < header_size) {
|
||||||
|
DEBUGP(DSCCP, "msgb > header_size %u %u\n",
|
||||||
|
msgb_l2len(msgb), header_size);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dt1->segmenting != 0) {
|
||||||
|
DEBUGP(DSCCP, "This packet has segmenting, not supported: %d\n", dt1->segmenting);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
result->destination_local_reference = &dt1->destination_local_reference;
|
||||||
|
|
||||||
|
/* some more size checks in here */
|
||||||
|
if (msgb_l2len(msgb) < variable_offset + dt1->variable_start + 1) {
|
||||||
|
DEBUGP(DSCCP, "Not enough space for variable start: %u %u\n",
|
||||||
|
msgb_l2len(msgb), dt1->variable_start);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
result->data_len = msgb->l2h[variable_offset + dt1->variable_start];
|
||||||
|
msgb->l3h = &msgb->l2h[dt1->variable_start + variable_offset + 1];
|
||||||
|
|
||||||
|
if (msgb_l3len(msgb) < result->data_len) {
|
||||||
|
DEBUGP(DSCCP, "Not enough room for the payload: %u %u\n",
|
||||||
|
msgb_l3len(msgb), result->data_len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _sccp_parse_udt(struct msgb *msgb, struct sccp_parse_result *result)
|
||||||
|
{
|
||||||
|
static const u_int32_t header_size = sizeof(struct sccp_data_unitdata);
|
||||||
|
static const u_int32_t called_offset = offsetof(struct sccp_data_unitdata, variable_called);
|
||||||
|
static const u_int32_t calling_offset = offsetof(struct sccp_data_unitdata, variable_calling);
|
||||||
|
static const u_int32_t data_offset = offsetof(struct sccp_data_unitdata, variable_data);
|
||||||
|
|
||||||
|
struct sccp_data_unitdata *udt = (struct sccp_data_unitdata *)msgb->l2h;
|
||||||
|
|
||||||
|
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 off */
|
||||||
|
if (copy_address(&result->called, called_offset + udt->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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (copy_address(&result->calling, calling_offset + udt->variable_calling, msgb) != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (check_address(&result->calling) != 0) {
|
||||||
|
DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n",
|
||||||
|
*(u_int8_t *)&result->called.address, result->called.ssn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we don't have enough size for the data */
|
||||||
|
if (msgb_l2len(msgb) < data_offset + udt->variable_data + 1) {
|
||||||
|
DEBUGP(DSCCP, "msgb < header + offset %u %u %u\n",
|
||||||
|
msgb_l2len(msgb), header_size, udt->variable_data);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
msgb->l3h = &udt->data[udt->variable_data];
|
||||||
|
|
||||||
|
if (msgb_l3len(msgb) != msgb->l3h[-1]) {
|
||||||
|
DEBUGP(DSCCP, "msgb is truncated is: %u should: %u\n",
|
||||||
|
msgb_l3len(msgb), msgb->l3h[-1]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send UDT. Currently we have a fixed address...
|
* Send UDT. Currently we have a fixed address...
|
||||||
*/
|
*/
|
||||||
|
@ -250,59 +521,15 @@ static int _sccp_send_data(int class, const struct sockaddr_sccp *in,
|
||||||
|
|
||||||
static int _sccp_handle_read(struct msgb *msgb)
|
static int _sccp_handle_read(struct msgb *msgb)
|
||||||
{
|
{
|
||||||
static const u_int32_t header_size = sizeof(struct sccp_data_unitdata);
|
|
||||||
static const u_int32_t called_offset = offsetof(struct sccp_data_unitdata, variable_called);
|
|
||||||
static const u_int32_t calling_offset = offsetof(struct sccp_data_unitdata, variable_calling);
|
|
||||||
static const u_int32_t data_offset = offsetof(struct sccp_data_unitdata, variable_data);
|
|
||||||
|
|
||||||
struct sccp_data_callback *cb;
|
struct sccp_data_callback *cb;
|
||||||
struct sccp_data_unitdata *udt = (struct sccp_data_unitdata *)msgb->l2h;
|
struct sccp_parse_result result;
|
||||||
struct sccp_address called, calling;
|
|
||||||
|
|
||||||
/* we don't have enough size for the struct */
|
if (_sccp_parse_udt(msgb, &result) != 0)
|
||||||
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 off */
|
|
||||||
if (copy_address(&called, called_offset + udt->variable_called, msgb) != 0)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (check_address(&called) != 0) {
|
cb = _find_ssn(result.called.ssn);
|
||||||
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);
|
|
||||||
if (!cb || !cb->read_cb) {
|
if (!cb || !cb->read_cb) {
|
||||||
DEBUGP(DSCCP, "No routing for UDT for called SSN: %u\n", called.ssn);
|
DEBUGP(DSCCP, "No routing for UDT for called SSN: %u\n", result.called.ssn);
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (copy_address(&calling, calling_offset + udt->variable_calling, msgb) != 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (check_address(&calling) != 0) {
|
|
||||||
DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n",
|
|
||||||
*(u_int8_t *)&called.address, called.ssn);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* we don't have enough size for the data */
|
|
||||||
if (msgb_l2len(msgb) < data_offset + udt->variable_data + 1) {
|
|
||||||
DEBUGP(DSCCP, "msgb < header + offset %u %u %u\n",
|
|
||||||
msgb_l2len(msgb), header_size, udt->variable_data);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
msgb->l3h = &udt->data[udt->variable_data];
|
|
||||||
|
|
||||||
if (msgb_l3len(msgb) != msgb->l3h[-1]) {
|
|
||||||
DEBUGP(DSCCP, "msgb is truncated %u %u\n",
|
|
||||||
msgb_l3len(msgb), msgb->l3h[-1]);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,7 +602,7 @@ static void _sccp_set_connection_state(struct sccp_connection *connection, int n
|
||||||
connection->state_cb(connection, old_state);
|
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 msgb *msgb;
|
||||||
struct sccp_connection_refused *ref;
|
struct sccp_connection_refused *ref;
|
||||||
|
@ -388,7 +615,7 @@ static int _sccp_send_refuse(struct sccp_connection_request *req, int cause)
|
||||||
|
|
||||||
ref = (struct sccp_connection_refused *) msgb_put(msgb, sizeof(*ref));
|
ref = (struct sccp_connection_refused *) msgb_put(msgb, sizeof(*ref));
|
||||||
ref->type = SCCP_MSG_TYPE_CREF;
|
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));
|
sizeof(struct sccp_source_reference));
|
||||||
ref->cause = cause;
|
ref->cause = cause;
|
||||||
ref->optional_start = 1;
|
ref->optional_start = 1;
|
||||||
|
@ -602,39 +829,17 @@ static int _sccp_send_connection_released(struct sccp_connection *conn, int caus
|
||||||
*/
|
*/
|
||||||
static int _sccp_handle_connection_request(struct msgb *msgb)
|
static int _sccp_handle_connection_request(struct msgb *msgb)
|
||||||
{
|
{
|
||||||
static const u_int32_t header_size =
|
struct sccp_parse_result result;
|
||||||
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_data_callback *cb;
|
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_connection *connection;
|
||||||
struct sccp_optional_data optional_data;
|
|
||||||
|
|
||||||
/* header check */
|
if (_sccp_parse_connection_request(msgb, &result) != 0)
|
||||||
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(&called, called_offset + req->variable_called, msgb) != 0)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (check_address(&called) != 0) {
|
cb = _find_ssn(result.called.ssn);
|
||||||
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);
|
|
||||||
if (!cb || !cb->accept_cb) {
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -652,28 +857,18 @@ static int _sccp_handle_connection_request(struct msgb *msgb)
|
||||||
* and send a connection confirm, otherwise we will send a refuseed
|
* and send a connection confirm, otherwise we will send a refuseed
|
||||||
* one....
|
* 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");
|
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);
|
talloc_free(connection);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
connection->incoming = 1;
|
connection->incoming = 1;
|
||||||
connection->destination_local_reference = req->source_local_reference;
|
connection->destination_local_reference = *result.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cb->accept_cb(connection, cb->accept_context) != 0) {
|
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);
|
_sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_REFUSED);
|
||||||
talloc_free(connection);
|
talloc_free(connection);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -685,7 +880,7 @@ static int _sccp_handle_connection_request(struct msgb *msgb)
|
||||||
if (_sccp_send_connection_confirm(connection) != 0) {
|
if (_sccp_send_connection_confirm(connection) != 0) {
|
||||||
DEBUGP(DSCCP, "Sending confirm failed... no available source reference?\n");
|
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);
|
_sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_REFUSED);
|
||||||
llist_del(&connection->list);
|
llist_del(&connection->list);
|
||||||
talloc_free(connection);
|
talloc_free(connection);
|
||||||
|
@ -696,39 +891,30 @@ static int _sccp_handle_connection_request(struct msgb *msgb)
|
||||||
/*
|
/*
|
||||||
* If we have data let us forward things.
|
* If we have data let us forward things.
|
||||||
*/
|
*/
|
||||||
if (optional_data.data_len != 0 && connection->data_cb) {
|
if (result.data_len != 0 && connection->data_cb) {
|
||||||
msgb->l3h = &msgb->l2h[optional_data.data_start];
|
connection->data_cb(connection, msgb, result.data_len);
|
||||||
connection->data_cb(connection, msgb, optional_data.data_len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle the release confirmed */
|
/* Handle the release confirmed */
|
||||||
static int _sccp_handle_connection_release_complete(struct msgb *data)
|
static int _sccp_handle_connection_release_complete(struct msgb *msgb)
|
||||||
{
|
{
|
||||||
static int header_size = sizeof(struct sccp_connection_release_complete);
|
struct sccp_parse_result result;
|
||||||
|
|
||||||
struct sccp_connection_release_complete *cmpl;
|
|
||||||
struct sccp_connection *conn;
|
struct sccp_connection *conn;
|
||||||
|
|
||||||
/* header check */
|
if (_sccp_parse_connection_release_complete(msgb, &result) != 0)
|
||||||
if (msgb_l2len(data) < header_size) {
|
|
||||||
DEBUGP(DSCCP, "msgb < header_size %u %u\n",
|
|
||||||
msgb_l2len(data), header_size);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
cmpl = (struct sccp_connection_release_complete *) data->l2h;
|
|
||||||
|
|
||||||
/* find the connection */
|
/* find the connection */
|
||||||
llist_for_each_entry(conn, &sccp_connections, list) {
|
llist_for_each_entry(conn, &sccp_connections, list) {
|
||||||
if (conn->data_cb
|
if (conn->data_cb
|
||||||
&& memcmp(&conn->source_local_reference,
|
&& memcmp(&conn->source_local_reference,
|
||||||
&cmpl->destination_local_reference,
|
result.destination_local_reference,
|
||||||
sizeof(conn->source_local_reference)) == 0
|
sizeof(conn->source_local_reference)) == 0
|
||||||
&& memcmp(&conn->destination_local_reference,
|
&& memcmp(&conn->destination_local_reference,
|
||||||
&cmpl->source_local_reference,
|
result.source_local_reference,
|
||||||
sizeof(conn->destination_local_reference)) == 0) {
|
sizeof(conn->destination_local_reference)) == 0) {
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
|
@ -745,57 +931,30 @@ found:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle the Data Form 1 message */
|
/* Handle the Data Form 1 message */
|
||||||
static int _sccp_handle_connection_dt1(struct msgb *data)
|
static int _sccp_handle_connection_dt1(struct msgb *msgb)
|
||||||
{
|
{
|
||||||
static int variable_offset = offsetof(struct sccp_data_form1, variable_start);
|
struct sccp_parse_result result;
|
||||||
static int header_size = sizeof(struct sccp_data_form1);
|
|
||||||
|
|
||||||
struct sccp_data_form1 *dt1 = (struct sccp_data_form1 *)data->l2h;
|
|
||||||
struct sccp_connection *conn;
|
struct sccp_connection *conn;
|
||||||
int size;
|
|
||||||
|
|
||||||
/* we don't have enough size for the struct */
|
if (_sccp_parse_connection_dt1(msgb, &result) != 0)
|
||||||
if (msgb_l2len(data) < header_size) {
|
|
||||||
DEBUGP(DSCCP, "msgb > header_size %u %u\n",
|
|
||||||
msgb_l2len(data), header_size);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
if (dt1->segmenting != 0) {
|
|
||||||
DEBUGP(DSCCP, "This packet has segmenting, not supported: %d\n", dt1->segmenting);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* lookup if we have a connection with the given reference */
|
/* lookup if we have a connection with the given reference */
|
||||||
llist_for_each_entry(conn, &sccp_connections, list) {
|
llist_for_each_entry(conn, &sccp_connections, list) {
|
||||||
if (conn->data_cb
|
if (conn->data_cb
|
||||||
&& memcmp(&conn->source_local_reference,
|
&& memcmp(&conn->source_local_reference,
|
||||||
&dt1->destination_local_reference,
|
result.destination_local_reference,
|
||||||
sizeof(conn->source_local_reference)) == 0) {
|
sizeof(conn->source_local_reference)) == 0) {
|
||||||
|
goto found;
|
||||||
/* some more size checks in here */
|
|
||||||
if (msgb_l2len(data) < variable_offset + dt1->variable_start + 1) {
|
|
||||||
DEBUGP(DSCCP, "Not enough space for variable start: %u %u\n",
|
|
||||||
msgb_l2len(data), dt1->variable_start);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
size = data->l2h[variable_offset + dt1->variable_start];
|
|
||||||
data->l3h = &data->l2h[dt1->variable_start + variable_offset + 1];
|
|
||||||
|
|
||||||
if (msgb_l3len(data) < size) {
|
|
||||||
DEBUGP(DSCCP, "Not enough room for the payload: %u %u\n",
|
|
||||||
msgb_l3len(data), size);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
conn->data_cb(conn, data, size);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUGP(DSCCP, "No connection found for dt1 data\n");
|
DEBUGP(DSCCP, "No connection found for dt1 data\n");
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
found:
|
||||||
|
conn->data_cb(conn, msgb, result.data_len);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* confirm a connection release */
|
/* confirm a connection release */
|
||||||
|
@ -830,30 +989,22 @@ static int _sccp_send_connection_release_complete(struct sccp_connection *connec
|
||||||
}
|
}
|
||||||
|
|
||||||
/* connection released, send a released confirm */
|
/* connection released, send a released confirm */
|
||||||
static int _sccp_handle_connection_released(struct msgb *data)
|
static int _sccp_handle_connection_released(struct msgb *msgb)
|
||||||
{
|
{
|
||||||
static int header_size = sizeof(struct sccp_connection_released);
|
struct sccp_parse_result result;
|
||||||
static int optional_offset = offsetof(struct sccp_connection_released, optional_start);
|
|
||||||
|
|
||||||
struct sccp_optional_data optional_data;
|
|
||||||
struct sccp_connection_released *rls = (struct sccp_connection_released *)data->l2h;
|
|
||||||
struct sccp_connection *conn;
|
struct sccp_connection *conn;
|
||||||
|
|
||||||
/* we don't have enough size for the struct */
|
if (_sccp_parse_connection_released(msgb, &result) == -1)
|
||||||
if (msgb_l2len(data) < header_size) {
|
|
||||||
DEBUGP(DSCCP, "msgb > header_size %u %u\n",
|
|
||||||
msgb_l2len(data), header_size);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
/* lookup if we have a connection with the given reference */
|
/* lookup if we have a connection with the given reference */
|
||||||
llist_for_each_entry(conn, &sccp_connections, list) {
|
llist_for_each_entry(conn, &sccp_connections, list) {
|
||||||
if (conn->data_cb
|
if (conn->data_cb
|
||||||
&& memcmp(&conn->source_local_reference,
|
&& memcmp(&conn->source_local_reference,
|
||||||
&rls->destination_local_reference,
|
result.destination_local_reference,
|
||||||
sizeof(conn->source_local_reference)) == 0
|
sizeof(conn->source_local_reference)) == 0
|
||||||
&& memcmp(&conn->destination_local_reference,
|
&& memcmp(&conn->destination_local_reference,
|
||||||
&rls->source_local_reference,
|
result.source_local_reference,
|
||||||
sizeof(conn->destination_local_reference)) == 0) {
|
sizeof(conn->destination_local_reference)) == 0) {
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
|
@ -865,16 +1016,9 @@ static int _sccp_handle_connection_released(struct msgb *data)
|
||||||
|
|
||||||
/* we have found a connection */
|
/* we have found a connection */
|
||||||
found:
|
found:
|
||||||
memset(&optional_data, 0, sizeof(optional_data));
|
|
||||||
if (_sccp_parse_optional_data(optional_offset + rls->optional_start, data, &optional_data) != 0) {
|
|
||||||
DEBUGP(DSCCP, "parsing of optional data failed.\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* optional data */
|
/* optional data */
|
||||||
if (optional_data.data_len != 0 && conn->data_cb) {
|
if (result.data_len != 0 && conn->data_cb) {
|
||||||
data->l3h = &data->l2h[optional_data.data_start];
|
conn->data_cb(conn, msgb, result.data_len);
|
||||||
conn->data_cb(conn, data, optional_data.data_len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* generate a response */
|
/* generate a response */
|
||||||
|
@ -888,28 +1032,17 @@ found:
|
||||||
|
|
||||||
static int _sccp_handle_connection_refused(struct msgb *msgb)
|
static int _sccp_handle_connection_refused(struct msgb *msgb)
|
||||||
{
|
{
|
||||||
static const u_int32_t header_size =
|
struct sccp_parse_result result;
|
||||||
sizeof(struct sccp_connection_refused);
|
|
||||||
static int optional_offset = offsetof(struct sccp_connection_refused, optional_start);
|
|
||||||
|
|
||||||
struct sccp_optional_data optional_data;
|
|
||||||
struct sccp_connection *conn;
|
struct sccp_connection *conn;
|
||||||
struct sccp_connection_refused *ref;
|
|
||||||
|
|
||||||
/* header check */
|
if (_sccp_parse_connection_refused(msgb, &result) != 0)
|
||||||
if (msgb_l2len(msgb) < header_size) {
|
|
||||||
DEBUGP(DSCCP, "msgb < header_size %u %u\n",
|
|
||||||
msgb_l2len(msgb), header_size);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
ref = (struct sccp_connection_refused *) msgb->l2h;
|
|
||||||
|
|
||||||
/* lookup if we have a connection with the given reference */
|
/* lookup if we have a connection with the given reference */
|
||||||
llist_for_each_entry(conn, &sccp_connections, list) {
|
llist_for_each_entry(conn, &sccp_connections, list) {
|
||||||
if (conn->incoming == 0 && conn->data_cb
|
if (conn->incoming == 0 && conn->data_cb
|
||||||
&& memcmp(&conn->source_local_reference,
|
&& memcmp(&conn->source_local_reference,
|
||||||
&ref->destination_local_reference,
|
result.destination_local_reference,
|
||||||
sizeof(conn->source_local_reference)) == 0) {
|
sizeof(conn->source_local_reference)) == 0) {
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
|
@ -919,16 +1052,9 @@ static int _sccp_handle_connection_refused(struct msgb *msgb)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
found:
|
found:
|
||||||
memset(&optional_data, 0, sizeof(optional_data));
|
|
||||||
if (_sccp_parse_optional_data(optional_offset + ref->optional_start, msgb, &optional_data) != 0) {
|
|
||||||
DEBUGP(DSCCP, "parsing of optional data failed.\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* optional data */
|
/* optional data */
|
||||||
if (optional_data.data_len != 0 && conn->data_cb) {
|
if (result.data_len != 0 && conn->data_cb) {
|
||||||
msgb->l3h = &msgb->l2h[optional_data.data_start];
|
conn->data_cb(conn, msgb, result.data_len);
|
||||||
conn->data_cb(conn, msgb, optional_data.data_len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -939,29 +1065,17 @@ found:
|
||||||
|
|
||||||
static int _sccp_handle_connection_confirm(struct msgb *msgb)
|
static int _sccp_handle_connection_confirm(struct msgb *msgb)
|
||||||
{
|
{
|
||||||
static u_int32_t header_size =
|
struct sccp_parse_result result;
|
||||||
sizeof(struct sccp_connection_confirm);
|
|
||||||
static const u_int32_t optional_offset =
|
|
||||||
offsetof(struct sccp_connection_confirm, optional_start);
|
|
||||||
|
|
||||||
struct sccp_optional_data optional_data;
|
|
||||||
struct sccp_connection *conn;
|
struct sccp_connection *conn;
|
||||||
struct sccp_connection_confirm *con;
|
|
||||||
|
|
||||||
/* header check */
|
if (_sccp_parse_connection_confirm(msgb, &result) != 0)
|
||||||
if (msgb_l2len(msgb) < header_size) {
|
|
||||||
DEBUGP(DSCCP, "msgb < header_size %u %u\n",
|
|
||||||
msgb_l2len(msgb), header_size);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
con = (struct sccp_connection_confirm *) msgb->l2h;
|
|
||||||
|
|
||||||
/* lookup if we have a connection with the given reference */
|
/* lookup if we have a connection with the given reference */
|
||||||
llist_for_each_entry(conn, &sccp_connections, list) {
|
llist_for_each_entry(conn, &sccp_connections, list) {
|
||||||
if (conn->incoming == 0 && conn->data_cb
|
if (conn->incoming == 0 && conn->data_cb
|
||||||
&& memcmp(&conn->source_local_reference,
|
&& memcmp(&conn->source_local_reference,
|
||||||
&con->destination_local_reference,
|
result.destination_local_reference,
|
||||||
sizeof(conn->source_local_reference)) == 0) {
|
sizeof(conn->source_local_reference)) == 0) {
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
|
@ -972,19 +1086,12 @@ static int _sccp_handle_connection_confirm(struct msgb *msgb)
|
||||||
|
|
||||||
found:
|
found:
|
||||||
/* copy the addresses of the connection */
|
/* copy the addresses of the connection */
|
||||||
conn->destination_local_reference = con->source_local_reference;
|
conn->destination_local_reference = *result.source_local_reference;
|
||||||
_sccp_set_connection_state(conn, SCCP_CONNECTION_STATE_ESTABLISHED);
|
_sccp_set_connection_state(conn, SCCP_CONNECTION_STATE_ESTABLISHED);
|
||||||
|
|
||||||
memset(&optional_data, 0, sizeof(optional_data));
|
|
||||||
if (_sccp_parse_optional_data(optional_offset + con->optional_start, msgb, &optional_data) != 0) {
|
|
||||||
DEBUGP(DSCCP, "parsing of optional data failed.\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* optional data */
|
/* optional data */
|
||||||
if (optional_data.data_len != 0 && conn->data_cb) {
|
if (result.data_len != 0 && conn->data_cb) {
|
||||||
msgb->l3h = &msgb->l2h[optional_data.data_start];
|
conn->data_cb(conn, msgb, result.data_len);
|
||||||
conn->data_cb(conn, msgb, optional_data.data_len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1161,6 +1268,49 @@ struct sccp_source_reference sccp_src_ref_from_int(u_int32_t int_ref)
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sccp_determine_msg_type(struct msgb *msg)
|
||||||
|
{
|
||||||
|
if (msgb_l2len(msg) < 1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return msg->l2h[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
int sccp_parse_header(struct msgb *msg, struct sccp_parse_result *result)
|
||||||
|
{
|
||||||
|
int type;
|
||||||
|
|
||||||
|
if (msgb_l2len(msg) < 1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
type = msg->l2h[0];
|
||||||
|
switch(type) {
|
||||||
|
case SCCP_MSG_TYPE_CR:
|
||||||
|
return _sccp_parse_connection_request(msg, result);
|
||||||
|
break;
|
||||||
|
case SCCP_MSG_TYPE_RLSD:
|
||||||
|
return _sccp_parse_connection_released(msg, result);
|
||||||
|
break;
|
||||||
|
case SCCP_MSG_TYPE_CREF:
|
||||||
|
return _sccp_parse_connection_refused(msg, result);
|
||||||
|
break;
|
||||||
|
case SCCP_MSG_TYPE_CC:
|
||||||
|
return _sccp_parse_connection_confirm(msg, result);
|
||||||
|
break;
|
||||||
|
case SCCP_MSG_TYPE_RLC:
|
||||||
|
return _sccp_parse_connection_release_complete(msg, result);
|
||||||
|
break;
|
||||||
|
case SCCP_MSG_TYPE_DT1:
|
||||||
|
return _sccp_parse_connection_dt1(msg, result);
|
||||||
|
break;
|
||||||
|
case SCCP_MSG_TYPE_UDT:
|
||||||
|
return _sccp_parse_udt(msg, result);
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static __attribute__((constructor)) void on_dso_load(void)
|
static __attribute__((constructor)) void on_dso_load(void)
|
||||||
{
|
{
|
||||||
tall_sccp_ctx = talloc_named_const(NULL, 1, "sccp");
|
tall_sccp_ctx = talloc_named_const(NULL, 1, "sccp");
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* SCCP testing code
|
* SCCP testing code
|
||||||
*
|
*
|
||||||
* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
|
* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||||
* (C) 2009 by on-waves.com
|
* (C) 2009 by On-Waves
|
||||||
*
|
*
|
||||||
* All Rights Reserved
|
* All Rights Reserved
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue