summaryrefslogtreecommitdiffstats
path: root/openbsc/src/libmgcp/mgcp_protocol.c
diff options
context:
space:
mode:
Diffstat (limited to 'openbsc/src/libmgcp/mgcp_protocol.c')
-rw-r--r--openbsc/src/libmgcp/mgcp_protocol.c436
1 files changed, 179 insertions, 257 deletions
diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c
index 607e230..beff981 100644
--- a/openbsc/src/libmgcp/mgcp_protocol.c
+++ b/openbsc/src/libmgcp/mgcp_protocol.c
@@ -36,39 +36,9 @@
#include <openbsc/mgcp.h>
#include <openbsc/mgcp_internal.h>
-/**
- * Macro for tokenizing MGCP messages and SDP in one go.
- *
- */
-#define MSG_TOKENIZE_START \
- line_start = 0; \
- for (i = 0; i < msgb_l3len(msg); ++i) { \
- /* we have a line end */ \
- if (msg->l3h[i] == '\n') { \
- /* skip the first line */ \
- if (line_start == 0) { \
- line_start = i + 1; \
- continue; \
- } \
- \
- /* check if we have a proper param */ \
- if (i - line_start == 1 && msg->l3h[line_start] == '\r') { \
- } else if (i - line_start > 2 \
- && islower(msg->l3h[line_start]) \
- && msg->l3h[line_start + 1] == '=') { \
- } else if (i - line_start < 3 \
- || msg->l3h[line_start + 1] != ':' \
- || msg->l3h[line_start + 2] != ' ') \
- goto error; \
- \
- msg->l3h[i] = '\0'; \
- if (msg->l3h[i-1] == '\r') \
- msg->l3h[i-1] = '\0';
-
-#define MSG_TOKENIZE_END \
- line_start = i + 1; \
- } \
- }
+#define for_each_line(input, line, save) \
+ for (line = strtok_r(input, "\r\n", &save); line; \
+ line = strtok_r(NULL, "\r\n", &save))
static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end);
@@ -227,42 +197,6 @@ struct msgb *mgcp_handle_message(struct mgcp_config *cfg, struct msgb *msg)
return resp;
}
-/* string tokenizer for the poor */
-static int find_msg_pointers(struct msgb *msg, struct mgcp_msg_ptr *ptrs, int ptrs_length)
-{
- int i, found = 0;
-
- int whitespace = 1;
- for (i = 0; i < msgb_l3len(msg) && ptrs_length > 0; ++i) {
- /* if we have a space we found an end */
- if (msg->l3h[i] == ' ' || msg->l3h[i] == '\r' || msg->l3h[i] == '\n') {
- if (!whitespace) {
- ++found;
- whitespace = 1;
- ptrs->length = i - ptrs->start - 1;
- ++ptrs;
- --ptrs_length;
- } else {
- /* skip any number of whitespace */
- }
-
- /* line end... stop */
- if (msg->l3h[i] == '\r' || msg->l3h[i] == '\n')
- break;
- } else if (msg->l3h[i] == '\r' || msg->l3h[i] == '\n') {
- /* line end, be done */
- break;
- } else if (whitespace) {
- whitespace = 0;
- ptrs->start = i;
- }
- }
-
- if (ptrs_length == 0)
- return -1;
- return found;
-}
-
/**
* We have a null terminated string with the endpoint name here. We only
* support two kinds. Simple ones as seen on the BSC level and the ones
@@ -327,48 +261,49 @@ static struct mgcp_endpoint *find_endpoint(struct mgcp_config *cfg, const char *
return NULL;
}
-int mgcp_analyze_header(struct mgcp_config *cfg, struct msgb *msg,
- struct mgcp_msg_ptr *ptr, int size,
+static int mgcp_analyze_header(struct mgcp_config *cfg, char *data,
const char **transaction_id, struct mgcp_endpoint **endp)
{
- int found;
+ int i = 0;
+ char *elem, *save;
*transaction_id = "000000";
- if (size < 3) {
- LOGP(DMGCP, LOGL_ERROR, "Not enough space in ptr\n");
- return -1;
- }
-
- found = find_msg_pointers(msg, ptr, size);
-
- if (found <= 3) {
- LOGP(DMGCP, LOGL_ERROR, "Gateway: Not enough params. Found: %d\n", found);
- return -1;
- }
-
- /*
- * replace the space with \0. the main method gurantess that
- * we still have + 1 for null termination
- */
- msg->l3h[ptr[3].start + ptr[3].length + 1] = '\0';
- msg->l3h[ptr[2].start + ptr[2].length + 1] = '\0';
- msg->l3h[ptr[1].start + ptr[1].length + 1] = '\0';
- msg->l3h[ptr[0].start + ptr[0].length + 1] = '\0';
-
- if (strncmp("1.0", (const char *)&msg->l3h[ptr[3].start], 3) != 0
- || strncmp("MGCP", (const char *)&msg->l3h[ptr[2].start], 4) != 0) {
- LOGP(DMGCP, LOGL_ERROR, "Wrong MGCP version. Not handling: '%s' '%s'\n",
- (const char *)&msg->l3h[ptr[3].start],
- (const char *)&msg->l3h[ptr[2].start]);
- return -1;
+ for (elem = strtok_r(data, " ", &save); elem;
+ elem = strtok_r(NULL, " ", &save)) {
+ switch (i) {
+ case 0:
+ *transaction_id = elem;
+ break;
+ case 1:
+ if (endp) {
+ *endp = find_endpoint(cfg, elem);
+ if (!*endp) {
+ LOGP(DMGCP, LOGL_ERROR,
+ "Unable to find Endpoint `%s'\n",
+ elem);
+ return -1;
+ }
+ }
+ break;
+ case 2:
+ if (strcmp("MGCP", elem)) {
+ LOGP(DMGCP, LOGL_ERROR,
+ "MGCP header parsing error\n");
+ return -1;
+ }
+ break;
+ case 3:
+ if (strcmp("1.0", elem)) {
+ LOGP(DMGCP, LOGL_ERROR, "MGCP version `%s' "
+ "not supported\n", elem);
+ return -1;
+ }
+ break;
+ }
+ i++;
}
- *transaction_id = (const char *)&msg->l3h[ptr[0].start];
- if (endp) {
- *endp = find_endpoint(cfg, (const char *)&msg->l3h[ptr[1].start]);
- return *endp == NULL;
- }
return 0;
}
@@ -400,12 +335,12 @@ static int verify_ci(const struct mgcp_endpoint *endp,
static struct msgb *handle_audit_endpoint(struct mgcp_config *cfg, struct msgb *msg)
{
- struct mgcp_msg_ptr data_ptrs[6];
int found;
const char *trans_id;
struct mgcp_endpoint *endp;
+ char *data = strtok((char *) msg->l3h, "\r\n");
- found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
+ found = mgcp_analyze_header(cfg, data, &trans_id, &endp);
if (found != 0)
return create_err_response(500, "AUEP", trans_id);
else
@@ -503,8 +438,6 @@ static int allocate_ports(struct mgcp_endpoint *endp)
static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
{
- struct mgcp_msg_ptr data_ptrs[6];
- int found, i, line_start;
const char *trans_id;
struct mgcp_trunk_config *tcfg;
struct mgcp_endpoint *endp;
@@ -513,33 +446,36 @@ static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
const char *local_options = NULL;
const char *callid = NULL;
const char *mode = NULL;
-
-
- found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
- if (found != 0)
- return create_err_response(510, "CRCX", trans_id);
-
- tcfg = endp->tcfg;
+ char *line, *save;
/* parse CallID C: and LocalParameters L: */
- MSG_TOKENIZE_START
- switch (msg->l3h[line_start]) {
- case 'L':
- local_options = (const char *) &msg->l3h[line_start + 3];
- break;
- case 'C':
- callid = (const char *) &msg->l3h[line_start + 3];
- break;
- case 'M':
- mode = (const char *) & msg->l3h[line_start + 3];
- break;
- default:
- LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
- msg->l3h[line_start], msg->l3h[line_start],
- ENDPOINT_NUMBER(endp));
- break;
+ for_each_line((char *) msg->l3h, line, save) {
+ /* skip first line */
+ if (line == (char *) msg->l3h) {
+ int found = mgcp_analyze_header(cfg, line, &trans_id, &endp);
+ if (found != 0)
+ return create_err_response(510, "CRCX", trans_id);
+
+ tcfg = endp->tcfg;
+ continue;
+ }
+
+ switch (line[0]) {
+ case 'L':
+ local_options = (const char *) line + 3;
+ break;
+ case 'C':
+ callid = (const char *) line + 3;
+ break;
+ case 'M':
+ mode = (const char *) line + 3;
+ break;
+ default:
+ LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
+ *line, *line, ENDPOINT_NUMBER(endp));
+ break;
+ }
}
- MSG_TOKENIZE_END
/* Check required data */
if (!callid || !mode) {
@@ -624,12 +560,6 @@ static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
create_transcoder(endp);
return create_response_with_sdp(endp, "CRCX", trans_id);
-error:
- LOGP(DMGCP, LOGL_ERROR, "Malformed line: %s on 0x%x with: line_start: %d %d\n",
- osmo_hexdump(msg->l3h, msgb_l3len(msg)),
- ENDPOINT_NUMBER(endp), line_start, i);
- return create_err_response(error_code, "CRCX", trans_id);
-
error2:
mgcp_free_endp(endp);
LOGP(DMGCP, LOGL_NOTICE, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp));
@@ -638,86 +568,88 @@ error2:
static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg)
{
- struct mgcp_msg_ptr data_ptrs[6];
- int found, i, line_start;
const char *trans_id;
struct mgcp_endpoint *endp;
int error_code = 500;
int silent = 0;
+ char *line, *save;
+
+ for_each_line((char *) msg->l3h, line, save) {
+ /* skip first line */
+ if (line == (char *) msg->l3h) {
+ int found = mgcp_analyze_header(cfg, line, &trans_id,
+ &endp);
+ if (found != 0)
+ return create_err_response(510, "MDCX",
+ trans_id);
+
+ if (endp->ci == CI_UNUSED) {
+ LOGP(DMGCP, LOGL_ERROR, "Endpoint is not "
+ "holding a connection. 0x%x\n",
+ ENDPOINT_NUMBER(endp));
+ return create_err_response(400, "MDCX", trans_id);
+ }
+ }
- found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
- if (found != 0)
- return create_err_response(510, "MDCX", trans_id);
-
- if (endp->ci == CI_UNUSED) {
- LOGP(DMGCP, LOGL_ERROR, "Endpoint is not holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp));
- return create_err_response(400, "MDCX", trans_id);
- }
-
- MSG_TOKENIZE_START
- switch (msg->l3h[line_start]) {
- case 'C': {
- if (verify_call_id(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
- goto error3;
- break;
- }
- case 'I': {
- if (verify_ci(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
- goto error3;
- break;
- }
- case 'L':
- /* skip */
- break;
- case 'M':
- if (parse_conn_mode((const char *)&msg->l3h[line_start + 3],
- &endp->conn_mode) != 0) {
- error_code = 517;
- goto error3;
+ switch (line[0]) {
+ case 'C': {
+ if (verify_call_id(endp, line + 3) != 0)
+ goto error3;
+ break;
}
- endp->orig_mode = endp->conn_mode;
- break;
- case 'Z':
- silent = strcmp("noanswer", (const char *)&msg->l3h[line_start + 3]) == 0;
- break;
- case '\0':
- /* SDP file begins */
- break;
- case 'a':
- case 'o':
- case 's':
- case 't':
- case 'v':
- /* skip these SDP attributes */
- break;
- case 'm': {
- int port;
- int payload;
- const char *param = (const char *)&msg->l3h[line_start];
-
- if (sscanf(param, "m=audio %d RTP/AVP %d", &port, &payload) == 2) {
- endp->net_end.rtp_port = htons(port);
- endp->net_end.rtcp_port = htons(port + 1);
- endp->net_end.payload_type = payload;
+ case 'I': {
+ if (verify_ci(endp, line + 3) != 0)
+ goto error3;
+ break;
}
- break;
- }
- case 'c': {
- char ipv4[16];
- const char *param = (const char *)&msg->l3h[line_start];
+ case 'L':
+ /* skip */
+ break;
+ case 'M':
+ if (parse_conn_mode(line + 3, &endp->conn_mode) != 0) {
+ error_code = 517;
+ goto error3;
+ }
+ endp->orig_mode = endp->conn_mode;
+ break;
+ case 'Z':
+ silent = strcmp("noanswer", line + 3) == 0;
+ break;
+ case '\0':
+ /* SDP file begins */
+ break;
+ case 'a':
+ case 'o':
+ case 's':
+ case 't':
+ case 'v':
+ /* skip these SDP attributes */
+ break;
+ case 'm': {
+ int port;
+ int payload;
+
+ if (sscanf(line, "m=audio %d RTP/AVP %d", &port, &payload) == 2) {
+ endp->net_end.rtp_port = htons(port);
+ endp->net_end.rtcp_port = htons(port + 1);
+ endp->net_end.payload_type = payload;
+ }
+ break;
+ }
+ case 'c': {
+ char ipv4[16];
- if (sscanf(param, "c=IN IP4 %15s", ipv4) == 1) {
- inet_aton(ipv4, &endp->net_end.addr);
+ if (sscanf(line, "c=IN IP4 %15s", ipv4) == 1) {
+ inet_aton(ipv4, &endp->net_end.addr);
+ }
+ break;
+ }
+ default:
+ LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
+ line[0], line[0], ENDPOINT_NUMBER(endp));
+ break;
}
- break;
- }
- default:
- LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
- msg->l3h[line_start], msg->l3h[line_start],
- ENDPOINT_NUMBER(endp));
- break;
}
- MSG_TOKENIZE_END
/* policy CB */
if (cfg->policy_cb) {
@@ -749,12 +681,6 @@ static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg)
return create_response_with_sdp(endp, "MDCX", trans_id);
-error:
- LOGP(DMGCP, LOGL_ERROR, "Malformed line: %s on 0x%x with: line_start: %d %d %d\n",
- osmo_hexdump(msg->l3h, msgb_l3len(msg)),
- ENDPOINT_NUMBER(endp), line_start, i, msg->l3h[line_start]);
- return create_err_response(error_code, "MDCX", trans_id);
-
error3:
return create_err_response(error_code, "MDCX", trans_id);
@@ -765,44 +691,47 @@ out_silent:
static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg)
{
- struct mgcp_msg_ptr data_ptrs[6];
- int found, i, line_start;
const char *trans_id;
struct mgcp_endpoint *endp;
int error_code = 400;
int silent = 0;
+ char *line, *save;
+
+ for_each_line((char *) msg->l3h, line, save) {
+ /* skip first line */
+ if ((char *) msg->l3h == line) {
+ int found = mgcp_analyze_header(cfg, line, &trans_id,
+ &endp);
+ if (found != 0)
+ return create_err_response(error_code, "DLCX",
+ trans_id);
+
+ if (!endp->allocated) {
+ LOGP(DMGCP, LOGL_ERROR, "Endpoint is not "
+ "used. 0x%x\n", ENDPOINT_NUMBER(endp));
+ return create_err_response(400, "DLCX",
+ trans_id);
+ }
+ }
- found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
- if (found != 0)
- return create_err_response(error_code, "DLCX", trans_id);
-
- if (!endp->allocated) {
- LOGP(DMGCP, LOGL_ERROR, "Endpoint is not used. 0x%x\n", ENDPOINT_NUMBER(endp));
- return create_err_response(400, "DLCX", trans_id);
- }
-
- MSG_TOKENIZE_START
- switch (msg->l3h[line_start]) {
- case 'C': {
- if (verify_call_id(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
- goto error3;
- break;
- }
- case 'I': {
- if (verify_ci(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
- goto error3;
- break;
- case 'Z':
- silent = strcmp("noanswer", (const char *)&msg->l3h[line_start + 3]) == 0;
- break;
- }
- default:
- LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
- msg->l3h[line_start], msg->l3h[line_start],
- ENDPOINT_NUMBER(endp));
- break;
+ switch (line[0]) {
+ case 'C':
+ if (verify_call_id(endp, line + 3) != 0)
+ goto error3;
+ break;
+ case 'I':
+ if (verify_ci(endp, line + 3) != 0)
+ goto error3;
+ break;
+ case 'Z':
+ silent = strcmp("noanswer", line + 3) == 0;
+ break;
+ default:
+ LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
+ line[0], line[0], ENDPOINT_NUMBER(endp));
+ break;
+ }
}
- MSG_TOKENIZE_END
/* policy CB */
if (cfg->policy_cb) {
@@ -838,12 +767,6 @@ static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg)
goto out_silent;
return create_ok_response(250, "DLCX", trans_id);
-error:
- LOGP(DMGCP, LOGL_ERROR, "Malformed line: %s on 0x%x with: line_start: %d %d\n",
- osmo_hexdump(msg->l3h, msgb_l3len(msg)),
- ENDPOINT_NUMBER(endp), line_start, i);
- return create_err_response(error_code, "DLCX", trans_id);
-
error3:
return create_err_response(error_code, "DLCX", trans_id);
@@ -853,13 +776,12 @@ out_silent:
static struct msgb *handle_rsip(struct mgcp_config *cfg, struct msgb *msg)
{
- struct mgcp_msg_ptr data_ptrs[6];
const char *trans_id;
struct mgcp_endpoint *endp;
int found;
+ char *data = strtok((char *) msg->l3h, "\r\n");
- found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs),
- &trans_id, &endp);
+ found = mgcp_analyze_header(cfg, data, &trans_id, &endp);
if (found != 0) {
LOGP(DMGCP, LOGL_ERROR, "Failed to find the endpoint.\n");
return NULL;
@@ -877,12 +799,12 @@ static struct msgb *handle_rsip(struct mgcp_config *cfg, struct msgb *msg)
*/
static struct msgb *handle_noti_req(struct mgcp_config *cfg, struct msgb *msg)
{
- struct mgcp_msg_ptr data_ptrs[6];
const char *trans_id;
struct mgcp_endpoint *endp;
int found;
+ char *data = strtok((char *) msg->l3h, "\r\n");
- found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
+ found = mgcp_analyze_header(cfg, data, &trans_id, &endp);
if (found != 0)
return create_err_response(400, "RQNT", trans_id);