403 lines
8.4 KiB
C
403 lines
8.4 KiB
C
/*
|
|
*
|
|
* Copyright (C) 2008 LGC Wireless, Inc
|
|
* Written by: Xinyu Yan <xyyan@lgcwireless.com>
|
|
*
|
|
*-
|
|
*/
|
|
#include "./include/isup_debug.h"
|
|
#include "./include/isup_public.h"
|
|
#include "./include/isup_if.h"
|
|
#include "./include/isup_struct.h"
|
|
#include "./include/isup_def.h"
|
|
#include "./include/isup_const.h"
|
|
|
|
#define MAX_ISUP_VAR 10
|
|
#define MAX_ISUP_OPT 50
|
|
|
|
struct param_unit {
|
|
u8 len;
|
|
u8 *ptr;
|
|
};
|
|
|
|
struct isup_gen_fmt {
|
|
u8 var_num;
|
|
u8 opt_num;
|
|
struct param_unit fix;
|
|
struct param_unit var[MAX_ISUP_VAR];
|
|
struct param_unit opt[MAX_ISUP_OPT];
|
|
};
|
|
|
|
#define MAX_ISUP_MSGTYPE 100 //not sure, just an assumption
|
|
#define LEN_OF_LV(ptr) (*ptr + 1)
|
|
#define LEN_OF_TLV(ptr) (*(ptr+1) + 2)
|
|
|
|
struct isup_fmt_desc {
|
|
u8 exist;
|
|
u8 fixed_len; /* fixed len start from message type(include) */
|
|
u8 var_num;
|
|
};
|
|
|
|
const static struct isup_fmt_desc fmt_desc_itu[MAX_ISUP_MSGTYPE] = {
|
|
{0},
|
|
{1, 6, 1}, //Initial address(1)
|
|
{1, 1, 1}, //Subsequent address(2)
|
|
{1,3,0},//Information request (national use)(3)
|
|
{1,3,0},//Information (national use)(4)
|
|
{1,2,0},//Continuity(5)
|
|
{1,3,0},//Address complete(6)
|
|
{1,3,0},//Connect(7)
|
|
{1,1,0},//Forward transfer(8)
|
|
{1,1,0},//Answer(9)
|
|
{0},//10
|
|
{0},//11
|
|
{1,1,1},//Release(12)
|
|
{1,2,0},//Suspend(13)
|
|
{1,2,0},//Resume(14)
|
|
{0},//15
|
|
{1,1,0},//Release complete(16)
|
|
{0},
|
|
{0},
|
|
{0},
|
|
{0},//Unblocking(20)
|
|
{0},
|
|
{0},//Unblocking acknowledgement(22)
|
|
{0},
|
|
{0},
|
|
{0},//25
|
|
{0},
|
|
{0},
|
|
{0},
|
|
{0},
|
|
{0},//30
|
|
{1,2,0},//Facility request(31)
|
|
{1,2,0},//Facility accepted(32)
|
|
{1,2,1},//Facility reject(33)
|
|
{0},
|
|
{0},//35
|
|
{0},//Loop Back Acknowledgement(36)
|
|
{0},
|
|
{0},
|
|
{0},
|
|
{0},//Pass-Along(40)
|
|
{0},
|
|
{0},
|
|
{0},
|
|
{1,2,0},//Call progress(44)
|
|
{1,1,1},//User-to-user information(45)
|
|
{0},//Unequipped CIC (national use)(46)
|
|
{1,1,1},//Confusion(47)
|
|
{0},//Overload(48)
|
|
{0},//Charge information (national use)(49)
|
|
{1,1,0},//Network resource management(50)
|
|
{1,1,0},//Facility (51)
|
|
{1,1,0},//User Part Test(52)
|
|
{1,1,0},//User Part Available(53)
|
|
{1,1,0},//Identification request(54)
|
|
{1,1,0},//Identification response(55)
|
|
{1,1,0},//Segmentation(56)
|
|
{0},
|
|
{0},
|
|
{0},
|
|
{0},//60
|
|
{0},
|
|
{0},
|
|
{0},
|
|
{1,1,0},//Loop Prevention(64)
|
|
{1,1,0},//Application transport message(65)
|
|
{1,1,0},//Pre-release information message (66)
|
|
};
|
|
|
|
const static struct isup_fmt_desc fmt_desc_ansi[MAX_ISUP_MSGTYPE] = {
|
|
{0},
|
|
{1, 5, 2}, //Initial address(1)
|
|
{1, 1, 1}, //Subsequent address(2)
|
|
{1,3,0},//Information request (national use)(3)
|
|
{1,3,0},//Information (national use)(4)
|
|
{1,2,0},//Continuity(5)
|
|
{1,3,0},//Address complete(6)
|
|
{1,3,0},//Connect(7)
|
|
{1,1,0},//Forward transfer(8)
|
|
{1,1,0},//Answer(9)
|
|
{0},//10
|
|
{0},//11
|
|
{1,1,1},//Release(12)
|
|
{1,2,0},//Suspend(13)
|
|
{1,2,0},//Resume(14)
|
|
{0},//15
|
|
{1,1,0},//Release complete(16)
|
|
{0},
|
|
{0},
|
|
{0},
|
|
{0},//Unblocking(20)
|
|
{0},
|
|
{0},//Unblocking acknowledgement(22)
|
|
{0},
|
|
{0},
|
|
{0},//25
|
|
{0},
|
|
{0},
|
|
{0},
|
|
{0},
|
|
{0},//30
|
|
{1,2,0},//Facility request(31)
|
|
{1,2,0},//Facility accepted(32)
|
|
{1,2,1},//Facility reject(33)
|
|
{0},
|
|
{0},//35
|
|
{0},//Loop Back Acknowledgement(36)
|
|
{0},
|
|
{0},
|
|
{0},
|
|
{0},//Pass-Along(40)
|
|
{0},
|
|
{0},
|
|
{0},
|
|
{1,2,0},//Call progress(44)
|
|
{1,1,1},//User-to-user information(45)
|
|
{0},//Unequipped CIC (national use)(46)
|
|
{1,1,1},//Confusion(47)
|
|
{0},//Overload(48)
|
|
{0},//Charge information (national use)(49)
|
|
{1,1,0},//Network resource management(50)
|
|
{1,1,0},//Facility (51)
|
|
{1,1,0},//User Part Test(52)
|
|
{1,1,0},//User Part Available(53)
|
|
{1,1,0},//Identification request(54)
|
|
{1,1,0},//Identification response(55)
|
|
{1,1,0},//Segmentation(56)
|
|
{0},
|
|
{0},
|
|
{0},
|
|
{0},//60
|
|
{0},
|
|
{0},
|
|
{0},
|
|
{1,1,0},//Loop Prevention(64)
|
|
{1,1,0},//Application transport message(65)
|
|
{1,1,0},//Pre-release information message (66)
|
|
};
|
|
|
|
int raw_to_fmt(struct isup_gen_fmt *fmt, u8 *raw_head, u16 raw_len, u8 variant)
|
|
{
|
|
int i;
|
|
const struct isup_fmt_desc *desc;
|
|
struct param_unit *opt;
|
|
u8 msg_type;
|
|
u8 *raw = raw_head;
|
|
|
|
msg_type = *raw;
|
|
if(msg_type >= MAX_ISUP_MSGTYPE)
|
|
return 0;
|
|
if(variant == VARIANT_ANSI)
|
|
desc = &fmt_desc_ansi[msg_type];
|
|
else
|
|
desc = &fmt_desc_itu[msg_type];
|
|
if(desc->exist == 0)
|
|
return 0;
|
|
|
|
memset(fmt, 0, sizeof(struct isup_gen_fmt));
|
|
|
|
// M Fixed //
|
|
fmt->fix.len = desc->fixed_len;
|
|
fmt->fix.ptr = raw;
|
|
raw += fmt->fix.len;
|
|
|
|
// M Variable //
|
|
fmt->var_num = desc->var_num;
|
|
raw += *raw;
|
|
if(fmt->var_num != 0)
|
|
{
|
|
for(i = 0; i < fmt->var_num; i++)
|
|
{
|
|
if(raw + LEN_OF_LV(raw) - raw_head > raw_len)
|
|
return -1;
|
|
fmt->var[i].len = LEN_OF_LV(raw);
|
|
fmt->var[i].ptr = raw;
|
|
raw += fmt->var[i].len;
|
|
}
|
|
}
|
|
|
|
// Option //
|
|
while(*raw != 0)
|
|
{
|
|
if(raw + LEN_OF_TLV(raw) - raw_head > raw_len)
|
|
return -1;
|
|
opt = &fmt->opt[fmt->opt_num++];
|
|
opt->len = LEN_OF_TLV(raw);
|
|
opt->ptr = raw;
|
|
raw += opt->len;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int param_need_merge(u8 param_name)
|
|
{
|
|
switch(param_name)
|
|
{
|
|
case ME_REDIRGNUM:
|
|
case ME_REDIRINFO:
|
|
case ME_ORIGCALDNUM:
|
|
case ME_LOCNMB:
|
|
case ME_LASDIVLINID:
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int param_already_exist(u8 *index, struct isup_gen_fmt *org, u8 param_name)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < org->opt_num; i++)
|
|
{
|
|
if(*(org->opt[i].ptr) == param_name)
|
|
{
|
|
*index = i;
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static u8 bw_call_ind[4];
|
|
void merge_cpg_acm(struct isup_gen_fmt *dst, struct isup_gen_fmt *cpg, struct isup_gen_fmt *acm)
|
|
{
|
|
int i;
|
|
u8 param_name;
|
|
u8 index;
|
|
|
|
memcpy(dst, cpg, sizeof(struct isup_gen_fmt));
|
|
|
|
/* backward call ind, from fix part to opt */
|
|
bw_call_ind[0] = ME_BACKCALLIND;
|
|
bw_call_ind[1] = 2;
|
|
memcpy(bw_call_ind+2, acm->fix.ptr+1, 2);
|
|
dst->opt[dst->opt_num].len = 4;
|
|
dst->opt[dst->opt_num].ptr = bw_call_ind;
|
|
dst->opt_num++;
|
|
|
|
for(i = 0; i < acm->opt_num; i++)
|
|
{
|
|
param_name = *(acm->opt[i].ptr);
|
|
/* discard echo control infomation */
|
|
if(param_name == ME_ECHOCNTRL)
|
|
continue;
|
|
if(param_already_exist(&index, dst, param_name) == 1)
|
|
memcpy(&dst->opt[index], &acm->opt[i], sizeof(struct param_unit));
|
|
else
|
|
memcpy(&dst->opt[dst->opt_num++], &acm->opt[i], sizeof(struct param_unit));
|
|
}
|
|
}
|
|
|
|
void merge_fmt(struct isup_gen_fmt *dst, struct isup_gen_fmt *org, struct isup_gen_fmt *add)
|
|
{
|
|
int i;
|
|
u8 param_name;
|
|
u8 index;
|
|
|
|
memcpy(dst, org, sizeof(struct isup_gen_fmt));
|
|
|
|
if(*(add->fix.ptr) == M_CPG)
|
|
memcpy(&dst->fix, &add->fix, sizeof(struct param_unit));
|
|
|
|
if(*(add->fix.ptr) == M_IAM)
|
|
{
|
|
for(i = 0; i < add->var_num; i++)
|
|
{
|
|
memcpy(&dst->var[i], &add->var[i], sizeof(struct param_unit));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(i = 0; i < org->var_num; i++)
|
|
{
|
|
memcpy(&dst->var[i], &org->var[i], sizeof(struct param_unit));
|
|
}
|
|
}
|
|
|
|
for(i = 0; i < add->opt_num; i++)
|
|
{
|
|
param_name = *(add->opt[i].ptr);
|
|
if(param_need_merge(param_name) == 0)
|
|
continue;
|
|
if(param_already_exist(&index, dst, param_name) == 1)
|
|
memcpy(&dst->opt[index], &add->opt[i], sizeof(struct param_unit));
|
|
else
|
|
memcpy(&dst->opt[dst->opt_num++], &add->opt[i], sizeof(struct param_unit));
|
|
}
|
|
}
|
|
|
|
int fmt_to_raw(u8 *raw_head, struct isup_gen_fmt *fmt)
|
|
{
|
|
u8 *raw = raw_head;
|
|
int i;
|
|
u8 pre_pointer;
|
|
u8 pre_varlen;
|
|
|
|
// M Fixed //
|
|
memcpy(raw, fmt->fix.ptr, fmt->fix.len);
|
|
raw += fmt->fix.len;
|
|
|
|
/* Set initial condition, note that if VAR not exist, it applys to OPT directly */
|
|
pre_varlen = fmt->var_num + 1;
|
|
pre_pointer = 1;
|
|
|
|
// M Variable //
|
|
if(fmt->var_num != 0)
|
|
{
|
|
for(i = 0; i < fmt->var_num; i++)
|
|
{
|
|
*raw = pre_pointer + pre_varlen - 1;
|
|
memcpy(raw+*raw, fmt->var[i].ptr, fmt->var[i].len);
|
|
pre_varlen = fmt->var[i].len;
|
|
pre_pointer = *(raw++);
|
|
}
|
|
|
|
// /* "pointer of optional part" is set to 0 first */
|
|
// *raw = 0;
|
|
}
|
|
|
|
// Option //
|
|
if(fmt->opt_num != 0)
|
|
{
|
|
/* Set "pointer of optional part" */
|
|
*raw = pre_pointer + pre_varlen - 1;
|
|
|
|
raw += *raw;
|
|
for(i = 0; i < fmt->opt_num; i++)
|
|
{
|
|
memcpy(raw, fmt->opt[i].ptr, fmt->opt[i].len);
|
|
raw += fmt->opt[i].len;
|
|
}
|
|
|
|
// /* Set "end of optional parameter" */
|
|
// *raw = 0;
|
|
}
|
|
|
|
/* Last octet set to 0. It may be "pointer of optional part" or "end of optional parameter" */
|
|
*(raw++) = 0;
|
|
if(fmt->opt_num == 0)
|
|
return raw-raw_head+pre_pointer + pre_varlen - 1 -1;
|
|
else
|
|
return raw-raw_head;
|
|
}
|
|
|
|
int isup_transit_msg(u8 *raw_dst, u8 *raw_add, u8 len_add, u8 *raw_org, u8 len_org, u8 variant)
|
|
{
|
|
struct isup_gen_fmt fmt_org;
|
|
struct isup_gen_fmt fmt_add;
|
|
struct isup_gen_fmt fmt_dst;
|
|
|
|
if(raw_to_fmt(&fmt_org, raw_org, len_org, variant)==0)
|
|
return 0;
|
|
if(raw_to_fmt(&fmt_add, raw_add, len_add, variant)==0)
|
|
return 0;
|
|
if((*(fmt_org.fix.ptr) == M_ACM) && (*(fmt_add.fix.ptr) == M_CPG))
|
|
merge_cpg_acm(&fmt_dst, &fmt_add, &fmt_org);
|
|
else
|
|
merge_fmt(&fmt_dst, &fmt_org, &fmt_add);
|
|
return fmt_to_raw(raw_dst, &fmt_dst);
|
|
}
|
|
|