130 lines
3.5 KiB
C
130 lines
3.5 KiB
C
#include <osmocom/core/utils.h>
|
|
|
|
#include "t62.h"
|
|
|
|
/* T.61 Table 1 */
|
|
const struct value_string t62_session_element_id_str[] = {
|
|
{ T62_SID_CSS, "Command Session Start" },
|
|
{ T62_SID_CSE, "Command Session End" },
|
|
{ T62_SID_CSA, "Command Session Abort" },
|
|
{ T62_SID_CSCC, "Command Session Change Control" },
|
|
{ T62_SID_CSUI, "Command Session User Information" },
|
|
{ T62_SID_RSSP, "Response Session Start Positive" },
|
|
{ T62_SID_RSSN, "Response Session Start Negative" },
|
|
{ T62_SID_RSEP, "Response Session End Positive" },
|
|
{ T62_SID_RSAP, "Response Session Abort Positive" },
|
|
{ T62_SID_RSCCP,"Response Session Change Control Positive" },
|
|
{ T62_SID_RSUI, "Response Session User Information" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
/* T.62 Table 2 */
|
|
const struct value_string t62_command_resp_str[] = {
|
|
{ T62_DCID_CDS, "Command Document Start" },
|
|
{ T62_DCID_CDC, "Command Document Continue" },
|
|
{ T62_DCID_CDE, "Command Document End" },
|
|
{ T62_DCID_CDR, "Command Document Resynchronize" },
|
|
{ T62_DCID_CDD, "Command Document Discard" },
|
|
{ T62_DCID_CDPB, "Command Document Page Boundary" },
|
|
{ T62_DCID_CDCL, "Command Document Capability List" },
|
|
{ T62_DCID_CDUI, "Command Document User Information" },
|
|
{ T62_DRID_RDEP, "Response Document End Positive" },
|
|
{ T62_DRID_RDRP, "Response Document Resynchronize Positive" },
|
|
{ T62_DRID_RDDP, "Response Document Discard Positive" },
|
|
{ T62_DRID_RDPBP, "Response Document Page Boundary Positive" },
|
|
{ T62_DRID_RDPBN, "Response Document Page Boundary Negative" },
|
|
{ T62_DRID_RDCLP, "Response Document Capability List Positive" },
|
|
{ T62_DRID_RDGR, "Response Document General Reject" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
|
|
struct t62_part {
|
|
struct llist_head list;
|
|
struct t62_part *parent;
|
|
|
|
uint8_t id;
|
|
const uint8_t *data;
|
|
uint16_t data_len;
|
|
|
|
struct llist_head children;
|
|
};
|
|
|
|
static struct t62_part *t62_part_alloc(void *ctx, struct t62_part *parent)
|
|
{
|
|
struct t62_part *part = talloc_zero(ctx, struct t62_part);
|
|
if (!part)
|
|
return NULL;
|
|
if (parent) {
|
|
part->parent = parent;
|
|
llist_add_tail(&part->list, &parent->children);
|
|
}
|
|
INIT_LLIST_HEAD(&part->children);
|
|
return part;
|
|
}
|
|
|
|
static void t62_part_free(struct t62_part *part)
|
|
{
|
|
if (part->parent)
|
|
llist_del(&part->list);
|
|
talloc_free(part);
|
|
}
|
|
|
|
/*! parse one T.62 parameter from msg starting at cur. Recurse if parameter is Parameter Group.
|
|
* \param[in] msg message buffer holding input data
|
|
* \param[in] cur pointer pointing to first byte of param (PI/PGI) inside msg
|
|
* \param[in] parent optional pointer to parent t62_part (in case of nesting)
|
|
* \returns parsed t62_param or NULL in case of error. */
|
|
struct t62_part *t62_parse_param(struct msgb *msg, uint8_t *cur, struct llist_head *parent)
|
|
{
|
|
struct t62_part *part = t62_part_alloc(parent, parent);
|
|
uint8_t pi;
|
|
uint16_t len;
|
|
|
|
/* FIXME: check msgb->length overflow everywhere below */
|
|
|
|
pi = *cur++;
|
|
if (*cur <= 254) {
|
|
/* 8-bit length */
|
|
len = *cur++;
|
|
} else {
|
|
/* 16-bit length */
|
|
cur++;
|
|
len = *cur++ << 8;
|
|
len |= *cur++;
|
|
}
|
|
|
|
part->id = pi;
|
|
if (len) {
|
|
part->data = cur;
|
|
part->data_len = len;
|
|
if (is_pgi(pi)) {
|
|
/* recurse if it's a group */
|
|
rc = t62_parse_param(msg, cur, part);
|
|
if (rc < 0) {
|
|
t62_part_free(part);
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
return part;
|
|
}
|
|
|
|
int t62_parse(struct msgb *msg, struct llist_head *parent)
|
|
{
|
|
uint8_t *cur;
|
|
uint8_t ci;
|
|
uint16_t len;
|
|
|
|
cur = msgb_l3h(msg);
|
|
|
|
root_part = t62_parse_param(msg, cur, NULL);
|
|
if (!root_part)
|
|
return -1;
|
|
|
|
/* check if there's user information after all (recursive) parts */
|
|
if (cur + root_part->data_len < msgb_l3len(msg)) {
|
|
/* FIXME */
|
|
}
|
|
}
|