From andreas at eversberg.eu Sun May 4 09:17:53 2014 From: andreas at eversberg.eu (Andreas Eversberg) Date: Sun, 04 May 2014 11:17:53 +0200 Subject: [PATCH 4/9] Add support for AMR frames to MNCC/RTP interface In-Reply-To: <20140429065219.GA3544@xiaoyu.lan> References: <1392793078-30854-1-git-send-email-jolly@eversberg.eu> <1392793078-30854-4-git-send-email-jolly@eversberg.eu> <20140320214603.GA11963@xiaoyu.lan> <20140417212945.GB31314@xiaoyu.lan> <5350F977.6060201@eversberg.eu> <20140420143020.GD14607@xiaoyu.lan> <20140429065219.GA3544@xiaoyu.lan> Message-ID: <536605C1.8080206@eversberg.eu> >>> i had that patch done already. (see attachment) >> what was the message id? I didn't see it. > Could you please answer this one? hi holger, sorry, i did not express myself well enough. i meant that i already wrote the patch, but did not send it to the mailing list. >> This lacks input validation. The code needs to check that the data >> we read is within the bounds of the msgb and the data we write is within >> the bounds too. i added a check that limits the GSM frames to 33 octets (full speech). (AMR requires only 31 octets + 1 octet length indicator.) an MNCC message has much larger msgb allocation when received. see attachment. best regards andreas From andreas at eversberg.eu Sun May 4 09:06:47 2014 From: andreas at eversberg.eu (Andreas Eversberg) Date: Sun, 04 May 2014 11:06:47 +0200 Subject: [PATCH 6/9] Add traffic forwarding via RTP to remote application In-Reply-To: <20140420143357.GE14607@xiaoyu.lan> References: <1392793078-30854-6-git-send-email-jolly@eversberg.eu> <20140309161952.GC6167@xiaoyu.lan> <531EAD2D.6000702@eversberg.eu> <20140314064042.GJ31238@xiaoyu.lan> <53242052.1070401@eversberg.eu> <20140316071240.GD27189@xiaoyu.lan> <53269940.7050101@eversberg.eu> <20140320214938.GB11963@xiaoyu.lan> <20140417212908.GA31314@xiaoyu.lan> <5350FCE7.9030401@eversberg.eu> <20140420143357.GE14607@xiaoyu.lan> Message-ID: <53660327.5000705@eversberg.eu> >> S_LCHAN_HANDOVER_FAIL, /* 04.08 Handover Failed */ >> S_LCHAN_HANDOVER_DETECT, /* 08.58 Handover Detect */ >> S_LCHAN_MEAS_REP, /* 08.58 Measurement Report */ >> + S_LCHAN_RTP_SOCKET_FREE, > Use the opportunity to write a bit of information here? Or maybe > just use S_CHALLOC_FREED to free rtp_socket and introduce a > S_CHALLOC_RESET to do it in the later case? > >> + struct lchan_signal_data sig; dear holger, i chose to use S_CHALLOC_* to trigger RTP socket freeing. see attached patch. best regards andreas From anayuso at sysmocom.de Mon May 5 14:09:51 2014 From: anayuso at sysmocom.de (Alvaro Neira Ayuso) Date: Mon, 5 May 2014 16:09:51 +0200 Subject: [osmo-bts PATCH 2/4 v12] src: Add OML support for sending failure message from manager In-Reply-To: <1398685472-19232-1-git-send-email-anayuso@sysmocom.de> References: <1398685472-19232-1-git-send-email-anayuso@sysmocom.de> Message-ID: <1399298991-14299-1-git-send-email-anayuso@sysmocom.de> With this patch, the manager monitors the sensors and send OML Failure message from the Manager to the BTS and the BTS to BSC, for having a report system of the sensors. Signed-off-by: Alvaro Neira Ayuso --- [changes in v12] * Changed check_oml_msg for making a general function that we can use in the future for check and restructure received oml message. src/osmo-bts-sysmo/Makefile.am | 4 +- src/osmo-bts-sysmo/main.c | 93 ++++++++++++++++++++ src/osmo-bts-sysmo/misc/sysmobts_mgr.c | 92 ++++++++++++++++++++ src/osmo-bts-sysmo/misc/sysmobts_mgr.h | 7 ++ src/osmo-bts-sysmo/misc/sysmobts_misc.c | 143 ++++++++++++++++++++++++++++++- src/osmo-bts-sysmo/misc/sysmobts_misc.h | 32 +++++++ src/osmo-bts-sysmo/utils.c | 139 ++++++++++++++++++++++++++++++ src/osmo-bts-sysmo/utils.h | 9 ++ 8 files changed, 516 insertions(+), 3 deletions(-) diff --git a/src/osmo-bts-sysmo/Makefile.am b/src/osmo-bts-sysmo/Makefile.am index 1c08af3..e9ba949 100644 --- a/src/osmo-bts-sysmo/Makefile.am +++ b/src/osmo-bts-sysmo/Makefile.am @@ -22,8 +22,8 @@ l1fwd_proxy_LDADD = $(top_builddir)/src/common/libbts.a $(COMMON_LDADD) sysmobts_mgr_SOURCES = \ misc/sysmobts_mgr.c misc/sysmobts_misc.c \ - misc/sysmobts_par.c misc/sysmobts_nl.c -sysmobts_mgr_LDADD = $(LIBOSMOCORE_LIBS) + misc/sysmobts_par.c misc/sysmobts_nl.c utils.c +sysmobts_mgr_LDADD = $(COMMON_LDADD) sysmobts_util_SOURCES = misc/sysmobts_util.c misc/sysmobts_par.c sysmobts_util_LDADD = $(LIBOSMOCORE_LIBS) diff --git a/src/osmo-bts-sysmo/main.c b/src/osmo-bts-sysmo/main.c index 921103e..acdf6fc 100644 --- a/src/osmo-bts-sysmo/main.c +++ b/src/osmo-bts-sysmo/main.c @@ -35,8 +35,10 @@ #include #include +#include #include #include +#include #include #include @@ -45,6 +47,9 @@ #include #include #include +#include + +#include "misc/sysmobts_mgr.h" #define SYSMOBTS_RF_LOCK_PATH "/var/lock/bts_rf_lock" @@ -258,6 +263,7 @@ static void signal_handler(int signal) case SIGINT: //osmo_signal_dispatch(SS_GLOBAL, S_GLOBAL_SHUTDOWN, NULL); bts_shutdown(bts, "SIGINT"); + unlink(SOCKET_PATH); break; case SIGABRT: case SIGUSR1: @@ -288,6 +294,86 @@ static int write_pid_file(char *procname) return 0; } +static int read_sock(struct osmo_fd *fd, unsigned int what) +{ + struct msgb *msg; + struct gsm_abis_mo *mo; + int rc; + + msg = oml_msgb_alloc(); + if (msg == NULL) { + LOGP(DL1C, LOGL_ERROR, "Failed alloc oml message.\n"); + return -1; + } + + rc = recv(fd->fd, msg->tail, msg->data_len, 0); + if (rc <= 0) { + close(fd->fd); + osmo_fd_unregister(fd); + fd->fd = -1; + goto err; + } + + msgb_put(msg, rc); + + if (check_oml_msg(msg) < 0) { + LOGP(DL1C, LOGL_ERROR, "Malformed receive message\n"); + goto err; + } + + mo = &bts->mo; + msg->trx = mo->bts->c0; + + return abis_oml_sendmsg(msg); + +err: + msgb_free(msg); + return -1; +} + +static int accept_unix_sock(struct osmo_fd *fd, unsigned int what) +{ + int sfd = fd->fd, cl; + struct osmo_fd *read_fd = (struct osmo_fd *)fd->data; + + if (read_fd->fd > -1) { + close(read_fd->fd); + osmo_fd_unregister(read_fd); + read_fd->fd = -1; + } + + cl = accept(sfd, NULL, NULL); + if (cl < 0) { + LOGP(DL1C, LOGL_ERROR, "Accept new unix domain connection.\n"); + return -1; + } + + read_fd->fd = cl; + if (osmo_fd_register(read_fd) != 0) { + LOGP(DL1C, LOGL_ERROR, "Register the read file desc.\n"); + close(cl); + read_fd->fd = -1; + return -1; + } + + return 0; +} + +static int oml_sock_unix_init(struct osmo_fd *accept, struct osmo_fd *read) +{ + int rc; + + accept->cb = accept_unix_sock; + read->cb = read_sock; + read->when = BSC_FD_READ; + read->fd = -1; + accept->data = read; + + rc = osmo_sock_unix_init_ofd(accept, SOCK_SEQPACKET, 0, SOCKET_PATH, + OSMO_SOCK_F_BIND | OSMO_SOCK_F_NONBLOCK); + return rc; +} + int main(int argc, char **argv) { struct stat st; @@ -295,6 +381,7 @@ int main(int argc, char **argv) struct gsm_bts_role_bts *btsb; struct e1inp_line *line; void *tall_msgb_ctx; + struct osmo_fd accept_fd, read_fd; int rc; tall_bts_ctx = talloc_named_const(NULL, 1, "OsmoBTS context"); @@ -371,6 +458,12 @@ int main(int argc, char **argv) exit(1); } + rc = oml_sock_unix_init(&accept_fd, &read_fd); + if (rc < 0) { + perror("Error creating socket domain creation"); + exit(1); + } + if (daemonize) { rc = osmo_daemonize(); if (rc < 0) { diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr.c b/src/osmo-bts-sysmo/misc/sysmobts_mgr.c index 6c64d0f..51fdd83 100644 --- a/src/osmo-bts-sysmo/misc/sysmobts_mgr.c +++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -47,7 +48,9 @@ static int no_eeprom_write = 0; static int daemonize = 0; +static int fd_unix = -1; void *tall_mgr_ctx; +static struct sbts2050_config_info confinfo; /* every 6 hours means 365*4 = 1460 EEprom writes per year (max) */ #define TEMP_TIMER_SECS (6 * 3600) @@ -55,7 +58,63 @@ void *tall_mgr_ctx; /* every 1 hours means 365*24 = 8760 EEprom writes per year (max) */ #define HOURS_TIMER_SECS (1 * 3600) +/* every 5 minutes try to reconnect if we have a problem in the communication*/ +#define CONNECT_TIMER_SECS 300 + #ifdef BUILD_SBTS2050 +static int trx_nr = -1; +static int state_connection; + +static struct osmo_timer_list connect_timer; +static void socket_connect_cb(void *data) +{ + fd_unix = osmo_sock_unix_init(SOCK_SEQPACKET, 0, SOCKET_PATH, + OSMO_SOCK_F_CONNECT); + if (fd_unix < 0) { + osmo_timer_schedule(&connect_timer, CONNECT_TIMER_SECS, 0); + return; + } + + state_connection = SYSMO_MGR_CONNECTED; +} + +static int check_temperature(struct uc *ucontrol0, int lowlimit, int highlimit, + int current_temp, + enum sbts2050_temp_sensor sensor, + enum sbts2050_alert_lvl alert) +{ + int rc; + + if (lowlimit >= current_temp || highlimit <= current_temp) { + switch (alert) { + case SBTS2050_WARN_ALERT: + rc = send_omlfailure(fd_unix, alert, sensor, &confinfo, + trx_nr); + break; + case SBTS2050_SEVERE_ALERT: + rc = send_omlfailure(fd_unix, alert, sensor, + &confinfo, trx_nr); + sbts2050_uc_power(ucontrol0, confinfo.master_power_act, + confinfo.slave_power_act, + confinfo.pa_power_act); + break; + default: + LOGP(DFIND, LOGL_ERROR, "Unknown alert type %d\n", + alert); + return -1; + } + } else { + return 0; + } + + state_connection = rc; + + if (state_connection == SYSMO_MGR_DISCONNECTED) + socket_connect_cb(NULL); + + return 1; +} + static struct osmo_timer_list temp_uc_timer; static void check_uctemp_timer_cb(void *data) { @@ -64,6 +123,33 @@ static void check_uctemp_timer_cb(void *data) sbts2050_uc_check_temp(ucontrol0, &temp_pa, &temp_board); + confinfo.temp_pa_cur = temp_pa; + confinfo.temp_board_cur = temp_board; + + check_temperature(ucontrol0, + confinfo.temp_min_pa_warn_limit, + confinfo.temp_max_pa_warn_limit, + temp_pa, SBTS2050_TEMP_PA, + SBTS2050_WARN_ALERT); + + check_temperature(ucontrol0, + confinfo.temp_min_pa_severe_limit, + confinfo.temp_max_pa_severe_limit, + temp_pa, SBTS2050_TEMP_PA, + SBTS2050_SEVERE_ALERT); + + check_temperature(ucontrol0, + confinfo.temp_min_board_warn_limit, + confinfo.temp_max_board_warn_limit, + temp_board, SBTS2050_TEMP_BOARD, + SBTS2050_WARN_ALERT); + + check_temperature(ucontrol0, + confinfo.temp_min_board_severe_limit, + confinfo.temp_max_board_severe_limit, + temp_board, SBTS2050_TEMP_BOARD, + SBTS2050_SEVERE_ALERT); + osmo_timer_schedule(&temp_uc_timer, TEMP_TIMER_SECS, 0); } #endif @@ -93,6 +179,7 @@ static void initialize_sbts2050(void) if (val != 0) return; } + trx_nr = val; ucontrol0.fd = osmo_serial_init(ucontrol0.path, 115200); if (ucontrol0.fd < 0) { @@ -101,6 +188,10 @@ static void initialize_sbts2050(void) return; } + /* start handle for reconnect the socket in case of error */ + connect_timer.cb = socket_connect_cb; + socket_connect_cb(NULL); + temp_uc_timer.cb = check_uctemp_timer_cb; temp_uc_timer.data = &ucontrol0; check_uctemp_timer_cb(&ucontrol0); @@ -169,6 +260,7 @@ static void signal_handler(int signal) case SIGINT: sysmobts_check_temp(no_eeprom_write); sysmobts_update_hours(no_eeprom_write); + close(fd_unix); exit(0); break; case SIGABRT: diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr.h b/src/osmo-bts-sysmo/misc/sysmobts_mgr.h index ddb6774..21f30a4 100644 --- a/src/osmo-bts-sysmo/misc/sysmobts_mgr.h +++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr.h @@ -7,4 +7,11 @@ enum { DFIND, }; +enum { + SYSMO_MGR_DISCONNECTED = 0, + SYSMO_MGR_CONNECTED, +}; + +#define SOCKET_PATH "/var/run/bts_oml" + #endif diff --git a/src/osmo-bts-sysmo/misc/sysmobts_misc.c b/src/osmo-bts-sysmo/misc/sysmobts_misc.c index 9ea26c2..2030888 100644 --- a/src/osmo-bts-sysmo/misc/sysmobts_misc.c +++ b/src/osmo-bts-sysmo/misc/sysmobts_misc.c @@ -29,14 +29,19 @@ #include #include #include +#include #include #include #include +#include #include #include #include +#include +#include +#include "utils.h" #include "btsconfig.h" #include "sysmobts_misc.h" #include "sysmobts_par.h" @@ -49,9 +54,145 @@ #define SERIAL_ALLOC_SIZE 300 #define SIZE_HEADER_RSP 5 #define SIZE_HEADER_CMD 4 - +#define OM_ALLOC_SIZE 1024 +#define OM_HEADROOM_SIZE 128 #ifdef BUILD_SBTS2050 +static void add_sw_descr(struct msgb *msg) +{ + char file_version[255]; + char file_id[255]; + + strncpy(file_id, "sysmomgr", sizeof("sysmomgr")); + file_id[sizeof(file_id) - 1] = '\0'; + strncpy(file_version, PACKAGE_VERSION, sizeof(PACKAGE_VERSION)); + file_version[sizeof(file_version) - 1] = '\0'; + msgb_v_put(msg, NM_ATT_SW_DESCR); + msgb_tl16v_put(msg, NM_ATT_FILE_ID, strlen(file_id), + (uint8_t *)file_id); + msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, strlen(file_version), + (uint8_t *)file_version); +} + +static void add_probable_cause(struct msgb *msg) +{ + msgb_tv_put(msg, NM_ATT_PROB_CAUSE, NM_PCAUSE_T_MANUF); + msgb_v_put(msg, 0); + msgb_v_put(msg, 0); +} + +static void add_oml_hdr_msg(struct msgb *msg, uint8_t msg_type, + uint8_t obj_class, uint8_t bts_nr, + uint8_t trx_nr, uint8_t ts_nr, int is_manuf) +{ + struct abis_om_fom_hdr *foh; + struct abis_om_hdr *omh; + + msg->l3h = msgb_push(msg, sizeof(*foh)); + foh = (struct abis_om_fom_hdr *) msg->l3h; + + foh->msg_type = msg_type; + foh->obj_class = obj_class; + foh->obj_inst.bts_nr = bts_nr; + foh->obj_inst.trx_nr = trx_nr; + foh->obj_inst.ts_nr = ts_nr; + + if (is_manuf) { + /* length byte, string + 0 termination */ + uint8_t *manuf = msgb_push(msg, 1 + sizeof(osmocom_magic)); + manuf[0] = strlen(osmocom_magic)+1; + memcpy(manuf+1, osmocom_magic, strlen(osmocom_magic)); + } + + msg->l2h = msgb_push(msg, sizeof(*omh)); + omh = (struct abis_om_hdr *) msg->l2h; + + if (is_manuf) + omh->mdisc = ABIS_OM_MDISC_MANUF; + else + omh->mdisc = ABIS_OM_MDISC_FOM; + omh->placement = ABIS_OM_PLACEMENT_ONLY; + omh->sequence = 0; + omh->length = msgb_l3len(msg); +} + +int send_omlfailure(int fd_unix, enum sbts2050_alert_lvl alert, + enum sbts2050_temp_sensor sensor, + struct sbts2050_config_info *add_info, int trx_nr) +{ + int rc; + struct msgb *msg; + const char *buf, *nsensor; + + msg = msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE, "OML"); + if (msg == NULL) { + LOGP(DTEMP, LOGL_ERROR, "Error creating oml msg\n"); + return -1; + } + + add_oml_hdr_msg(msg, NM_MT_FAILURE_EVENT_REP, 0, 0, trx_nr, 255, 0); + + msgb_tv_put(msg, NM_ATT_EVENT_TYPE, NM_EVT_ENV_FAIL); + + switch (alert) { + case SBTS2050_WARN_ALERT: + msgb_tv_put(msg, NM_ATT_SEVERITY, NM_SEVER_WARNING); + break; + case SBTS2050_SEVERE_ALERT: + msgb_tv_put(msg, NM_ATT_SEVERITY, NM_SEVER_CRITICAL); + break; + default: + LOGP(DTEMP, LOGL_ERROR, "Unknown attr severity type %d\n", + alert); + goto err; + } + + add_probable_cause(msg); + + add_sw_descr(msg); + + switch (sensor) { + case SBTS2050_TEMP_BOARD: + buf = "Unusual temperature on the Board"; + nsensor = "Board"; + break; + case SBTS2050_TEMP_PA: + buf = "Unusual temperature on the PA"; + nsensor = "PA"; + break; + default: + LOGP(DTEMP, LOGL_ERROR, "Unknown sensor type %d\n", sensor); + goto err; + } + strncpy(add_info->name_sensor, nsensor, sizeof(add_info->name_sensor)); + add_info->name_sensor[sizeof(add_info->name_sensor) - 1] = '\0'; + + msgb_tl16v_put(msg, NM_ATT_ADD_TEXT, strlen(buf), (const uint8_t *)buf); + + /* If we need to send this structure to other machine, we need to pass + * the integer inside the structure to internet format (big endian) + */ + msgb_tl16v_put(msg, NM_ATT_ADD_INFO, + sizeof(struct sbts2050_config_info), + (const uint8_t *)add_info); + + prepend_oml_ipa_header(msg); + + rc = send(fd_unix, msg->data, msg->len, 0); + if (rc < 0 || rc != msg->len) { + LOGP(DTEMP, LOGL_ERROR, "Error writting in unix socket\n"); + close(fd_unix); + msgb_free(msg); + return SYSMO_MGR_DISCONNECTED; + } + + msgb_free(msg); + return SYSMO_MGR_CONNECTED; +err: + msgb_free(msg); + return -1; +} + /********************************************************************** * Functions read/write from serial interface *********************************************************************/ diff --git a/src/osmo-bts-sysmo/misc/sysmobts_misc.h b/src/osmo-bts-sysmo/misc/sysmobts_misc.h index 01878f2..c22a54b 100644 --- a/src/osmo-bts-sysmo/misc/sysmobts_misc.h +++ b/src/osmo-bts-sysmo/misc/sysmobts_misc.h @@ -32,6 +32,34 @@ struct ucinfo { int pa; }; +enum sbts2050_alert_lvl { + SBTS2050_WARN_ALERT, + SBTS2050_SEVERE_ALERT +}; + +enum sbts2050_temp_sensor { + SBTS2050_TEMP_BOARD, + SBTS2050_TEMP_PA +}; + +struct sbts2050_config_info { + char name_sensor[8]; + int temp_max_pa_warn_limit; + int temp_min_pa_warn_limit; + int temp_max_pa_severe_limit; + int temp_min_pa_severe_limit; + int temp_max_board_warn_limit; + int temp_min_board_warn_limit; + int temp_max_board_severe_limit; + int temp_min_board_severe_limit; + int reduce_max_power; + int slave_power_act; + int master_power_act; + int pa_power_act; + int temp_pa_cur; + int temp_board_cur; +}; + int sysmobts_temp_get(enum sysmobts_temp_sensor sensor, enum sysmobts_temp_type type); @@ -43,6 +71,10 @@ void sbts2050_uc_power(struct uc *ucontrol, int pmaster, int pslave, int ppa); int sbts2050_uc_status(struct uc *ucontrol, enum sbts2050_status_rqt status); +int send_omlfailure(int fd_unix, enum sbts2050_alert_lvl alert, + enum sbts2050_temp_sensor sensor, + struct sbts2050_config_info *add_info, int trx_nr); + int sysmobts_update_hours(int no_epprom_write); enum sysmobts_firmware_type { diff --git a/src/osmo-bts-sysmo/utils.c b/src/osmo-bts-sysmo/utils.c index af1e5d2..36ba198 100644 --- a/src/osmo-bts-sysmo/utils.c +++ b/src/osmo-bts-sysmo/utils.c @@ -27,6 +27,9 @@ #include #include +#include +#include + #include "femtobts.h" #include "l1_if.h" @@ -147,3 +150,139 @@ int sysmobts_get_power_trx(struct gsm_bts_trx *trx) return power_transmitter; } + +void prepend_oml_ipa_header(struct msgb *msg) +{ + struct ipaccess_head *hh; + + hh = (struct ipaccess_head *) msgb_push(msg, sizeof(*hh)); + hh->proto = IPAC_PROTO_OML; + hh->len = htons(msg->len - sizeof(struct ipaccess_head)); +} + +/** + * \brief Check that the data in \param msg is a proper OML message + * + * This function verifies that the data in \param in msg is a proper + * OML message and can be handled by later functions. In the successful + * case the msg->l2h will now point to the OML header and the msg->l3h + * will point to the FOM header. The value of l2h/l3h is undefined in + * case the verification of the \param msg is failing. + * + * \param msg The message to analyze. msg->len starting from msg->data + * will be analyzed. + * \return This function returns the msg with the l2h/l3h pointers in the right + * direction on success and on failure, in the case that the msg doesn't contain + * the OML header or the OML header values aren't the expect, the function + * doesn't set the l2h and l3h. In the case that the msg don't contains the FOM + * header or the FOM header values aren't the expect, the function set the l2h + * but doesn't set the l3h. + */ + +int check_oml_msg(struct msgb *msg) +{ + struct ipaccess_head *hh; + struct abis_om_hdr *omh; + int abis_oml_hdr_len; + char label_id[255]; + + if (msg->len < sizeof(struct ipaccess_head)) { + LOGP(DL1C, LOGL_ERROR, "Ipa header insufficient space %d %d\n", + msg->len, sizeof(struct ipaccess_head)); + return -1; + } + + hh = (struct ipaccess_head *)msg->data; + + if (hh->proto != IPAC_PROTO_OML) { + LOGP(DL1C, LOGL_ERROR, "Incorrect ipa header protocol %x %x\n", + hh->proto, IPAC_PROTO_OML); + return -1; + } + + if (ntohs(hh->len) != msg->len - sizeof(struct ipaccess_head)) { + LOGP(DL1C, LOGL_ERROR, "Incorrect ipa header msg size %d %d\n", + ntohs(hh->len), msg->len - sizeof(struct ipaccess_head)); + return -1; + } + + msgb_pull(msg, sizeof(struct ipaccess_head)); + + abis_oml_hdr_len = sizeof(struct abis_om_hdr); + + if (msg->len < abis_oml_hdr_len) { + LOGP(DL1C, LOGL_ERROR, "Om header insufficient space %d %d\n", + msg->len, abis_oml_hdr_len); + return -1; + } + + msg->l2h = msg->data; + + omh = (struct abis_om_hdr *) msg->l2h; + + if (omh->mdisc != ABIS_OM_MDISC_FOM && + omh->mdisc != ABIS_OM_MDISC_MANUF) { + LOGP(DL1C, LOGL_ERROR, "Incorrect om mdisc value %x\n", + omh->mdisc); + return -1; + } + + if (omh->placement != ABIS_OM_PLACEMENT_ONLY) { + LOGP(DL1C, LOGL_ERROR, "Incorrect om placement value %x %x\n", + omh->placement, ABIS_OM_PLACEMENT_ONLY); + return -1; + } + + if (omh->sequence != 0) { + LOGP(DL1C, LOGL_ERROR, "Incorrect om sequence value %d\n", + omh->sequence); + return -1; + } + + if (omh->length != sizeof(struct abis_om_fom_hdr)) { + LOGP(DL1C, LOGL_ERROR, "Incorrect om length value %d %d\n", + omh->length, sizeof(struct abis_om_fom_hdr)); + return -1; + } + + if (omh->mdisc == ABIS_OM_MDISC_MANUF) { + abis_oml_hdr_len += sizeof(ipaccess_magic); + + if (msg->len < abis_oml_hdr_len) { + LOGP(DL1C, LOGL_ERROR, + "ID manuf label insufficient space %d %d\n", + msg->len, abis_oml_hdr_len); + return -1; + } + } + + abis_oml_hdr_len += sizeof(struct abis_om_fom_hdr); + + if (msg->len < abis_oml_hdr_len) { + LOGP(DL1C, LOGL_ERROR, "Fom header insufficient space %d %d\n", + msg->len, abis_oml_hdr_len); + return -1; + } + + msg->l3h = msg->data + sizeof(struct abis_om_hdr); + + if (omh->mdisc == ABIS_OM_MDISC_MANUF) { + strncpy(label_id, (const char *) msg->l3h + 1, + sizeof(ipaccess_magic) + 1); + + if (strncmp(ipaccess_magic, label_id, + sizeof(ipaccess_magic) + 1) == 0) + msg->l3h = msg->l3h + sizeof(ipaccess_magic) + 1; + else if (strncmp(osmocom_magic, label_id, + sizeof(osmocom_magic) + 1) == 0) + msg->l3h = msg->l3h + sizeof(osmocom_magic) + 1; + else { + msg->l3h = NULL; + LOGP(DL1C, LOGL_ERROR, + "Manuf Label Unknown %s\n", label_id); + return -1; + } + } + + return 0; +} + diff --git a/src/osmo-bts-sysmo/utils.h b/src/osmo-bts-sysmo/utils.h index aef774c..b1ca0c0 100644 --- a/src/osmo-bts-sysmo/utils.h +++ b/src/osmo-bts-sysmo/utils.h @@ -13,4 +13,13 @@ int sysmobts_select_femto_band(struct gsm_bts_trx *trx, uint16_t arfcn); int sysmobts_get_nominal_power(struct gsm_bts_trx *trx); int sysmobts_get_power_trx(struct gsm_bts_trx *trx); + +struct msgb; + +static const char osmocom_magic[] = "org.osmocom"; +static const char ipaccess_magic[] = "com.ipaccess"; + +void prepend_oml_ipa_header(struct msgb *msg); + +int check_oml_msg(struct msgb *msg); #endif -- 1.7.10.4 From holger at freyther.de Thu May 15 20:27:34 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Thu, 15 May 2014 22:27:34 +0200 Subject: [osmo-bts PATCH 2/4 v12] src: Add OML support for sending failure message from manager In-Reply-To: <1399298991-14299-1-git-send-email-anayuso@sysmocom.de> References: <1398685472-19232-1-git-send-email-anayuso@sysmocom.de> <1399298991-14299-1-git-send-email-anayuso@sysmocom.de> Message-ID: <20140515202734.GB21990@xiaoyu.lan> On Mon, May 05, 2014 at 04:09:51PM +0200, Alvaro Neira Ayuso wrote: > With this patch, the manager monitors the sensors and send > OML Failure message from the Manager to the BTS and the BTS > to BSC, for having a report system of the sensors. Sorry but the above is not too clear. Please try again. > +static struct osmo_timer_list connect_timer; > +static void socket_connect_cb(void *data) > +{ > + fd_unix = osmo_sock_unix_init(SOCK_SEQPACKET, 0, SOCKET_PATH, > + OSMO_SOCK_F_CONNECT); > + if (fd_unix < 0) { > + osmo_timer_schedule(&connect_timer, CONNECT_TIMER_SECS, 0); What prevents socket_connect_cb(NULL) be called _while_ the timer is pending? While timers for check_temperature and socket_connect_cb might match now one should make sure the timer is stopped. > +static int check_temperature(struct uc *ucontrol0, int lowlimit, int highlimit, > @@ -169,6 +260,7 @@ static void signal_handler(int signal) > case SIGINT: > sysmobts_check_temp(no_eeprom_write); > sysmobts_update_hours(no_eeprom_write); > + close(fd_unix); > exit(0); Well, if we close it we should set fd_unix to -1 and unregister the fd. This might not be signal-safe, so why to close it at all? > + char file_version[255]; > + char file_id[255]; > + > + strncpy(file_id, "sysmomgr", sizeof("sysmomgr")); > + file_id[sizeof(file_id) - 1] = '\0'; > + strncpy(file_version, PACKAGE_VERSION, sizeof(PACKAGE_VERSION)); > + file_version[sizeof(file_version) - 1] = '\0'; > + msgb_v_put(msg, NM_ATT_SW_DESCR); > + msgb_tl16v_put(msg, NM_ATT_FILE_ID, strlen(file_id), > + (uint8_t *)file_id); > + msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, strlen(file_version), > + (uint8_t *)file_version); That is odd. You use "sizeof" which includes the NUL and then you use strlen on file_id which will remove the NUL. This appears to be not consistent. > + if (is_manuf) { > + /* length byte, string + 0 termination */ > + uint8_t *manuf = msgb_push(msg, 1 + sizeof(osmocom_magic)); > + manuf[0] = strlen(osmocom_magic)+1; > + memcpy(manuf+1, osmocom_magic, strlen(osmocom_magic)); > + } The sizes look odd here. Sure you want to have one byte for the length, the string and the NUL byte but you expect/assume that the msg is NUL at strlen(osmocom_magic)+1. Maybe it is better to not make this assumption? > + strncpy(add_info->name_sensor, nsensor, sizeof(add_info->name_sensor)); > + /* If we need to send this structure to other machine, we need to pass > + * the integer inside the structure to internet format (big endian) > + */ > + msgb_tl16v_put(msg, NM_ATT_ADD_INFO, > + sizeof(struct sbts2050_config_info), > + (const uint8_t *)add_info); yes? but it is sent to a BSC which might be another machine? Is this relevant? From anayuso at sysmocom.de Sat May 17 08:45:50 2014 From: anayuso at sysmocom.de (Alvaro Neira Ayuso) Date: Sat, 17 May 2014 10:45:50 +0200 Subject: [osmo-bts PATCH 1/3 v13] src: Add beginnings of a OML router and create Failure Messages in the sysmobts-manager In-Reply-To: <1399298991-14299-1-git-send-email-anayuso@sysmocom.de> References: <1399298991-14299-1-git-send-email-anayuso@sysmocom.de> Message-ID: <1400316350-23951-1-git-send-email-anayuso@sysmocom.de> From: ?lvaro Neira Ayuso Make the sysmobts listen for OML messages on a Unix Domain Socket. Messages passing a sanity check will be forwarded to the BSC. In case the sysmobts-mgr detects a temperature above or below temperature threshold an OML failure message will be sent to the BTS. Signed-off-by: Alvaro Neira Ayuso --- [changes in v13] * Deleted the socket connect timer in case that the connection is successful. * Removed the function close when the sysmobts-mgr receives the signal SIGINT. * Fixed inconsistence when we make the information that we use for initialize the attributes NM_ATT_SW_DESCR and NM_ATT_FILE_VERSION. * Fixed inconsistence when we make and add the manufacturer Id label. In the last, I have assumed wrong that always we have NUL termination. And too moved this part of code to utils for doing a new function for adding the manufacturer label ID. * Removed a irrelevant commentary when we add the attribute NM_ATT_ADD_INFO. src/osmo-bts-sysmo/Makefile.am | 4 +- src/osmo-bts-sysmo/main.c | 95 ++++++++++++++++++ src/osmo-bts-sysmo/misc/sysmobts_mgr.c | 92 ++++++++++++++++++ src/osmo-bts-sysmo/misc/sysmobts_mgr.h | 7 ++ src/osmo-bts-sysmo/misc/sysmobts_misc.c | 138 +++++++++++++++++++++++++- src/osmo-bts-sysmo/misc/sysmobts_misc.h | 32 +++++++ src/osmo-bts-sysmo/utils.c | 160 +++++++++++++++++++++++++++++++ src/osmo-bts-sysmo/utils.h | 16 ++++ 8 files changed, 541 insertions(+), 3 deletions(-) diff --git a/src/osmo-bts-sysmo/Makefile.am b/src/osmo-bts-sysmo/Makefile.am index 1c08af3..e9ba949 100644 --- a/src/osmo-bts-sysmo/Makefile.am +++ b/src/osmo-bts-sysmo/Makefile.am @@ -22,8 +22,8 @@ l1fwd_proxy_LDADD = $(top_builddir)/src/common/libbts.a $(COMMON_LDADD) sysmobts_mgr_SOURCES = \ misc/sysmobts_mgr.c misc/sysmobts_misc.c \ - misc/sysmobts_par.c misc/sysmobts_nl.c -sysmobts_mgr_LDADD = $(LIBOSMOCORE_LIBS) + misc/sysmobts_par.c misc/sysmobts_nl.c utils.c +sysmobts_mgr_LDADD = $(COMMON_LDADD) sysmobts_util_SOURCES = misc/sysmobts_util.c misc/sysmobts_par.c sysmobts_util_LDADD = $(LIBOSMOCORE_LIBS) diff --git a/src/osmo-bts-sysmo/main.c b/src/osmo-bts-sysmo/main.c index 20cfe9c..bd6a181 100644 --- a/src/osmo-bts-sysmo/main.c +++ b/src/osmo-bts-sysmo/main.c @@ -35,8 +35,10 @@ #include #include +#include #include #include +#include #include #include @@ -45,6 +47,9 @@ #include #include #include +#include + +#include "misc/sysmobts_mgr.h" #define SYSMOBTS_RF_LOCK_PATH "/var/lock/bts_rf_lock" @@ -258,6 +263,7 @@ static void signal_handler(int signal) case SIGINT: //osmo_signal_dispatch(SS_GLOBAL, S_GLOBAL_SHUTDOWN, NULL); bts_shutdown(bts, "SIGINT"); + unlink(SOCKET_PATH); break; case SIGABRT: case SIGUSR1: @@ -288,6 +294,88 @@ static int write_pid_file(char *procname) return 0; } +static int read_sock(struct osmo_fd *fd, unsigned int what) +{ + struct msgb *msg; + struct gsm_abis_mo *mo; + int rc; + + msg = oml_msgb_alloc(); + if (msg == NULL) { + LOGP(DL1C, LOGL_ERROR, + "Failed to allocate oml msgb.\n"); + return -1; + } + + rc = recv(fd->fd, msg->tail, msg->data_len, 0); + if (rc <= 0) { + close(fd->fd); + osmo_fd_unregister(fd); + fd->fd = -1; + goto err; + } + + msgb_put(msg, rc); + + if (check_oml_msg(msg) < 0) { + LOGP(DL1C, LOGL_ERROR, "Malformed receive message\n"); + goto err; + } + + mo = &bts->mo; + msg->trx = mo->bts->c0; + + return abis_oml_sendmsg(msg); + +err: + msgb_free(msg); + return -1; +} + +static int accept_unix_sock(struct osmo_fd *fd, unsigned int what) +{ + int sfd = fd->fd, cl; + struct osmo_fd *read_fd = (struct osmo_fd *)fd->data; + + if (read_fd->fd > -1) { + close(read_fd->fd); + osmo_fd_unregister(read_fd); + read_fd->fd = -1; + } + + cl = accept(sfd, NULL, NULL); + if (cl < 0) { + LOGP(DL1C, LOGL_ERROR, "Failed to accept. errno: %s.\n", + strerror(errno)); + return -1; + } + + read_fd->fd = cl; + if (osmo_fd_register(read_fd) != 0) { + LOGP(DL1C, LOGL_ERROR, "Register the read file desc.\n"); + close(cl); + read_fd->fd = -1; + return -1; + } + + return 0; +} + +static int oml_sock_unix_init(struct osmo_fd *accept, struct osmo_fd *read) +{ + int rc; + + accept->cb = accept_unix_sock; + read->cb = read_sock; + read->when = BSC_FD_READ; + read->fd = -1; + accept->data = read; + + rc = osmo_sock_unix_init_ofd(accept, SOCK_SEQPACKET, 0, SOCKET_PATH, + OSMO_SOCK_F_BIND | OSMO_SOCK_F_NONBLOCK); + return rc; +} + int main(int argc, char **argv) { struct stat st; @@ -295,6 +383,7 @@ int main(int argc, char **argv) struct gsm_bts_role_bts *btsb; struct e1inp_line *line; void *tall_msgb_ctx; + struct osmo_fd accept_fd, read_fd; int rc; tall_bts_ctx = talloc_named_const(NULL, 1, "OsmoBTS context"); @@ -373,6 +462,12 @@ int main(int argc, char **argv) exit(1); } + rc = oml_sock_unix_init(&accept_fd, &read_fd); + if (rc < 0) { + perror("Error creating socket domain creation"); + exit(1); + } + if (daemonize) { rc = osmo_daemonize(); if (rc < 0) { diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr.c b/src/osmo-bts-sysmo/misc/sysmobts_mgr.c index 6c64d0f..3148c7d 100644 --- a/src/osmo-bts-sysmo/misc/sysmobts_mgr.c +++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -48,6 +49,7 @@ static int no_eeprom_write = 0; static int daemonize = 0; void *tall_mgr_ctx; +static struct sbts2050_config_info confinfo; /* every 6 hours means 365*4 = 1460 EEprom writes per year (max) */ #define TEMP_TIMER_SECS (6 * 3600) @@ -55,8 +57,66 @@ void *tall_mgr_ctx; /* every 1 hours means 365*24 = 8760 EEprom writes per year (max) */ #define HOURS_TIMER_SECS (1 * 3600) +/* every 5 minutes try to reconnect if we have a problem in the communication*/ +#define CONNECT_TIMER_SECS 300 + #ifdef BUILD_SBTS2050 +static int fd_unix = -1; +static int trx_nr = -1; +static int state_connection; + static struct osmo_timer_list temp_uc_timer; +static struct osmo_timer_list connect_timer; +static void socket_connect_cb(void *data) +{ + fd_unix = osmo_sock_unix_init(SOCK_SEQPACKET, 0, SOCKET_PATH, + OSMO_SOCK_F_CONNECT); + if (fd_unix < 0) { + osmo_timer_schedule(&connect_timer, CONNECT_TIMER_SECS, 0); + return; + } + + osmo_timer_del(&connect_timer); + state_connection = SYSMO_MGR_CONNECTED; +} + +static int check_temperature(struct uc *ucontrol0, int lowlimit, int highlimit, + int current_temp, + enum sbts2050_temp_sensor sensor, + enum sbts2050_alert_lvl alert) +{ + int rc; + + if (lowlimit >= current_temp || highlimit <= current_temp) { + switch (alert) { + case SBTS2050_WARN_ALERT: + rc = send_omlfailure(fd_unix, alert, sensor, &confinfo, + trx_nr); + break; + case SBTS2050_SEVERE_ALERT: + rc = send_omlfailure(fd_unix, alert, sensor, + &confinfo, trx_nr); + sbts2050_uc_power(ucontrol0, confinfo.master_power_act, + confinfo.slave_power_act, + confinfo.pa_power_act); + break; + default: + LOGP(DFIND, LOGL_ERROR, "Unknown alert type %d\n", + alert); + return -1; + } + } else { + return 0; + } + + state_connection = rc; + + if (state_connection == SYSMO_MGR_DISCONNECTED) + socket_connect_cb(NULL); + + return 1; +} + static void check_uctemp_timer_cb(void *data) { int temp_pa = 0, temp_board = 0; @@ -64,6 +124,33 @@ static void check_uctemp_timer_cb(void *data) sbts2050_uc_check_temp(ucontrol0, &temp_pa, &temp_board); + confinfo.temp_pa_cur = temp_pa; + confinfo.temp_board_cur = temp_board; + + check_temperature(ucontrol0, + confinfo.temp_min_pa_warn_limit, + confinfo.temp_max_pa_warn_limit, + temp_pa, SBTS2050_TEMP_PA, + SBTS2050_WARN_ALERT); + + check_temperature(ucontrol0, + confinfo.temp_min_pa_severe_limit, + confinfo.temp_max_pa_severe_limit, + temp_pa, SBTS2050_TEMP_PA, + SBTS2050_SEVERE_ALERT); + + check_temperature(ucontrol0, + confinfo.temp_min_board_warn_limit, + confinfo.temp_max_board_warn_limit, + temp_board, SBTS2050_TEMP_BOARD, + SBTS2050_WARN_ALERT); + + check_temperature(ucontrol0, + confinfo.temp_min_board_severe_limit, + confinfo.temp_max_board_severe_limit, + temp_board, SBTS2050_TEMP_BOARD, + SBTS2050_SEVERE_ALERT); + osmo_timer_schedule(&temp_uc_timer, TEMP_TIMER_SECS, 0); } #endif @@ -93,6 +180,7 @@ static void initialize_sbts2050(void) if (val != 0) return; } + trx_nr = val; ucontrol0.fd = osmo_serial_init(ucontrol0.path, 115200); if (ucontrol0.fd < 0) { @@ -101,6 +189,10 @@ static void initialize_sbts2050(void) return; } + /* start handle for reconnect the socket in case of error */ + connect_timer.cb = socket_connect_cb; + socket_connect_cb(NULL); + temp_uc_timer.cb = check_uctemp_timer_cb; temp_uc_timer.data = &ucontrol0; check_uctemp_timer_cb(&ucontrol0); diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr.h b/src/osmo-bts-sysmo/misc/sysmobts_mgr.h index ddb6774..21f30a4 100644 --- a/src/osmo-bts-sysmo/misc/sysmobts_mgr.h +++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr.h @@ -7,4 +7,11 @@ enum { DFIND, }; +enum { + SYSMO_MGR_DISCONNECTED = 0, + SYSMO_MGR_CONNECTED, +}; + +#define SOCKET_PATH "/var/run/bts_oml" + #endif diff --git a/src/osmo-bts-sysmo/misc/sysmobts_misc.c b/src/osmo-bts-sysmo/misc/sysmobts_misc.c index 9ea26c2..2417c3d 100644 --- a/src/osmo-bts-sysmo/misc/sysmobts_misc.c +++ b/src/osmo-bts-sysmo/misc/sysmobts_misc.c @@ -29,14 +29,19 @@ #include #include #include +#include #include #include #include +#include #include #include #include +#include +#include +#include "utils.h" #include "btsconfig.h" #include "sysmobts_misc.h" #include "sysmobts_par.h" @@ -49,9 +54,140 @@ #define SERIAL_ALLOC_SIZE 300 #define SIZE_HEADER_RSP 5 #define SIZE_HEADER_CMD 4 - +#define OM_ALLOC_SIZE 1024 +#define OM_HEADROOM_SIZE 128 #ifdef BUILD_SBTS2050 +static void add_sw_descr(struct msgb *msg) +{ + char file_version[255]; + char file_id[255]; + + strncpy(file_id, "sysmomgr", strlen("sysmomgr")); + file_id[sizeof(file_id) - 1] = '\0'; + strncpy(file_version, PACKAGE_VERSION, strlen(PACKAGE_VERSION)); + file_version[sizeof(file_version) - 1] = '\0'; + msgb_v_put(msg, NM_ATT_SW_DESCR); + msgb_tl16v_put(msg, NM_ATT_FILE_ID, strlen(file_id), + (uint8_t *)file_id); + msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, strlen(file_version), + (uint8_t *)file_version); +} + +static void add_probable_cause(struct msgb *msg) +{ + msgb_tv_put(msg, NM_ATT_PROB_CAUSE, NM_PCAUSE_T_MANUF); + msgb_v_put(msg, 0); + msgb_v_put(msg, 0); +} + +static void add_oml_hdr_msg(struct msgb *msg, uint8_t msg_type, + uint8_t obj_class, uint8_t bts_nr, + uint8_t trx_nr, uint8_t ts_nr, int is_manuf) +{ + struct abis_om_fom_hdr *foh; + struct abis_om_hdr *omh; + + msg->l3h = msgb_push(msg, sizeof(*foh)); + foh = (struct abis_om_fom_hdr *) msg->l3h; + + foh->msg_type = msg_type; + foh->obj_class = obj_class; + foh->obj_inst.bts_nr = bts_nr; + foh->obj_inst.trx_nr = trx_nr; + foh->obj_inst.ts_nr = ts_nr; + + if (is_manuf) + add_manufacturer_id_label(msg, OSMOCOM_MANUF_ID); + + msg->l2h = msgb_push(msg, sizeof(*omh)); + omh = (struct abis_om_hdr *) msg->l2h; + + if (is_manuf) + omh->mdisc = ABIS_OM_MDISC_MANUF; + else + omh->mdisc = ABIS_OM_MDISC_FOM; + omh->placement = ABIS_OM_PLACEMENT_ONLY; + omh->sequence = 0; + omh->length = msgb_l3len(msg); +} + +int send_omlfailure(int fd_unix, enum sbts2050_alert_lvl alert, + enum sbts2050_temp_sensor sensor, + struct sbts2050_config_info *add_info, int trx_nr) +{ + int rc; + struct msgb *msg; + const char *buf, *nsensor; + + msg = msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE, "OML"); + if (msg == NULL) { + LOGP(DTEMP, LOGL_ERROR, "Failed to allocate oml msgb\n"); + return -1; + } + + add_oml_hdr_msg(msg, NM_MT_FAILURE_EVENT_REP, 0, 0, trx_nr, 255, 0); + + msgb_tv_put(msg, NM_ATT_EVENT_TYPE, NM_EVT_ENV_FAIL); + + switch (alert) { + case SBTS2050_WARN_ALERT: + msgb_tv_put(msg, NM_ATT_SEVERITY, NM_SEVER_WARNING); + break; + case SBTS2050_SEVERE_ALERT: + msgb_tv_put(msg, NM_ATT_SEVERITY, NM_SEVER_CRITICAL); + break; + default: + LOGP(DTEMP, LOGL_ERROR, "Unknown attr severity type %d\n", + alert); + goto err; + } + + add_probable_cause(msg); + + add_sw_descr(msg); + + switch (sensor) { + case SBTS2050_TEMP_BOARD: + buf = "Unusual temperature on the Board"; + nsensor = "Board"; + break; + case SBTS2050_TEMP_PA: + buf = "Unusual temperature on the PA"; + nsensor = "PA"; + break; + default: + LOGP(DTEMP, LOGL_ERROR, "Unknown sensor type %d\n", sensor); + goto err; + } + strncpy(add_info->name_sensor, nsensor, sizeof(add_info->name_sensor)); + add_info->name_sensor[sizeof(add_info->name_sensor) - 1] = '\0'; + + msgb_tl16v_put(msg, NM_ATT_ADD_TEXT, strlen(buf), (const uint8_t *)buf); + + msgb_tl16v_put(msg, NM_ATT_ADD_INFO, + sizeof(struct sbts2050_config_info), + (const uint8_t *)add_info); + + prepend_oml_ipa_header(msg); + + rc = send(fd_unix, msg->data, msg->len, 0); + if (rc < 0 || rc != msg->len) { + LOGP(DTEMP, LOGL_ERROR, + "send error %s during send the Failure Event Report msg\n", + strerror(errno)); + close(fd_unix); + msgb_free(msg); + return SYSMO_MGR_DISCONNECTED; + } + + msgb_free(msg); + return SYSMO_MGR_CONNECTED; +err: + msgb_free(msg); + return -1; +} + /********************************************************************** * Functions read/write from serial interface *********************************************************************/ diff --git a/src/osmo-bts-sysmo/misc/sysmobts_misc.h b/src/osmo-bts-sysmo/misc/sysmobts_misc.h index 01878f2..c22a54b 100644 --- a/src/osmo-bts-sysmo/misc/sysmobts_misc.h +++ b/src/osmo-bts-sysmo/misc/sysmobts_misc.h @@ -32,6 +32,34 @@ struct ucinfo { int pa; }; +enum sbts2050_alert_lvl { + SBTS2050_WARN_ALERT, + SBTS2050_SEVERE_ALERT +}; + +enum sbts2050_temp_sensor { + SBTS2050_TEMP_BOARD, + SBTS2050_TEMP_PA +}; + +struct sbts2050_config_info { + char name_sensor[8]; + int temp_max_pa_warn_limit; + int temp_min_pa_warn_limit; + int temp_max_pa_severe_limit; + int temp_min_pa_severe_limit; + int temp_max_board_warn_limit; + int temp_min_board_warn_limit; + int temp_max_board_severe_limit; + int temp_min_board_severe_limit; + int reduce_max_power; + int slave_power_act; + int master_power_act; + int pa_power_act; + int temp_pa_cur; + int temp_board_cur; +}; + int sysmobts_temp_get(enum sysmobts_temp_sensor sensor, enum sysmobts_temp_type type); @@ -43,6 +71,10 @@ void sbts2050_uc_power(struct uc *ucontrol, int pmaster, int pslave, int ppa); int sbts2050_uc_status(struct uc *ucontrol, enum sbts2050_status_rqt status); +int send_omlfailure(int fd_unix, enum sbts2050_alert_lvl alert, + enum sbts2050_temp_sensor sensor, + struct sbts2050_config_info *add_info, int trx_nr); + int sysmobts_update_hours(int no_epprom_write); enum sysmobts_firmware_type { diff --git a/src/osmo-bts-sysmo/utils.c b/src/osmo-bts-sysmo/utils.c index af1e5d2..2da1228 100644 --- a/src/osmo-bts-sysmo/utils.c +++ b/src/osmo-bts-sysmo/utils.c @@ -27,6 +27,9 @@ #include #include +#include +#include + #include "femtobts.h" #include "l1_if.h" @@ -147,3 +150,160 @@ int sysmobts_get_power_trx(struct gsm_bts_trx *trx) return power_transmitter; } + +void prepend_oml_ipa_header(struct msgb *msg) +{ + struct ipaccess_head *hh; + + hh = (struct ipaccess_head *) msgb_push(msg, sizeof(*hh)); + hh->proto = IPAC_PROTO_OML; + hh->len = htons(msg->len - sizeof(struct ipaccess_head)); +} + +/** + * \brief Check that the data in \param msg is a proper OML message + * + * This function verifies that the data in \param in msg is a proper + * OML message and can be handled by later functions. In the successful + * case the msg->l2h will now point to the OML header and the msg->l3h + * will point to the FOM header. The value of l2h/l3h is undefined in + * case the verification of the \param msg is failing. + * + * \param msg The message to analyze. msg->len starting from msg->data + * will be analyzed. + * \return This function returns the msg with the l2h/l3h pointers in the right + * direction on success and on failure, in the case that the msg doesn't contain + * the OML header or the OML header values aren't the expect, the function + * doesn't set the l2h and l3h. In the case that the msg don't contains the FOM + * header or the FOM header values aren't the expect, the function set the l2h + * but doesn't set the l3h. + */ + +int check_oml_msg(struct msgb *msg) +{ + struct ipaccess_head *hh; + struct abis_om_hdr *omh; + int abis_oml_hdr_len; + char label_id[255]; + + if (msg->len < sizeof(struct ipaccess_head)) { + LOGP(DL1C, LOGL_ERROR, "Ipa header insufficient space %d %d\n", + msg->len, sizeof(struct ipaccess_head)); + return -1; + } + + hh = (struct ipaccess_head *)msg->data; + + if (hh->proto != IPAC_PROTO_OML) { + LOGP(DL1C, LOGL_ERROR, "Incorrect ipa header protocol %x %x\n", + hh->proto, IPAC_PROTO_OML); + return -1; + } + + if (ntohs(hh->len) != msg->len - sizeof(struct ipaccess_head)) { + LOGP(DL1C, LOGL_ERROR, "Incorrect ipa header msg size %d %d\n", + ntohs(hh->len), msg->len - sizeof(struct ipaccess_head)); + return -1; + } + + msgb_pull(msg, sizeof(struct ipaccess_head)); + + abis_oml_hdr_len = sizeof(struct abis_om_hdr); + + if (msg->len < abis_oml_hdr_len) { + LOGP(DL1C, LOGL_ERROR, "Om header insufficient space %d %d\n", + msg->len, abis_oml_hdr_len); + return -1; + } + + msg->l2h = msg->data; + + omh = (struct abis_om_hdr *) msg->l2h; + + if (omh->mdisc != ABIS_OM_MDISC_FOM && + omh->mdisc != ABIS_OM_MDISC_MANUF) { + LOGP(DL1C, LOGL_ERROR, "Incorrect om mdisc value %x\n", + omh->mdisc); + return -1; + } + + if (omh->placement != ABIS_OM_PLACEMENT_ONLY) { + LOGP(DL1C, LOGL_ERROR, "Incorrect om placement value %x %x\n", + omh->placement, ABIS_OM_PLACEMENT_ONLY); + return -1; + } + + if (omh->sequence != 0) { + LOGP(DL1C, LOGL_ERROR, "Incorrect om sequence value %d\n", + omh->sequence); + return -1; + } + + if (omh->length != sizeof(struct abis_om_fom_hdr)) { + LOGP(DL1C, LOGL_ERROR, "Incorrect om length value %d %d\n", + omh->length, sizeof(struct abis_om_fom_hdr)); + return -1; + } + + if (omh->mdisc == ABIS_OM_MDISC_MANUF) { + abis_oml_hdr_len += sizeof(ipaccess_magic); + + if (msg->len < abis_oml_hdr_len) { + LOGP(DL1C, LOGL_ERROR, + "ID manuf label insufficient space %d %d\n", + msg->len, abis_oml_hdr_len); + return -1; + } + } + + abis_oml_hdr_len += sizeof(struct abis_om_fom_hdr); + + if (msg->len < abis_oml_hdr_len) { + LOGP(DL1C, LOGL_ERROR, "Fom header insufficient space %d %d\n", + msg->len, abis_oml_hdr_len); + return -1; + } + + msg->l3h = msg->data + sizeof(struct abis_om_hdr); + + if (omh->mdisc == ABIS_OM_MDISC_MANUF) { + strncpy(label_id, (const char *) msg->l3h + 1, + sizeof(ipaccess_magic) + 1); + + if (strncmp(ipaccess_magic, label_id, + sizeof(ipaccess_magic) + 1) == 0) + msg->l3h = msg->l3h + sizeof(ipaccess_magic) + 1; + else if (strncmp(osmocom_magic, label_id, + sizeof(osmocom_magic) + 1) == 0) + msg->l3h = msg->l3h + sizeof(osmocom_magic) + 1; + else { + msg->l3h = NULL; + LOGP(DL1C, LOGL_ERROR, + "Manuf Label Unknown %s\n", label_id); + return -1; + } + } + + return 0; +} + +int add_manufacturer_id_label(struct msgb *msg, int manuf_type_id) +{ + uint8_t *manuf; + + switch (manuf_type_id) { + case IPACCESS_MANUF_ID: + manuf = msgb_push(msg, 1 + sizeof(ipaccess_magic)); + manuf[0] = sizeof(ipaccess_magic); + memcpy(manuf+1, ipaccess_magic, sizeof(ipaccess_magic)); + break; + case OSMOCOM_MANUF_ID: + manuf = msgb_push(msg, 1 + sizeof(osmocom_magic)); + manuf[0] = sizeof(osmocom_magic); + memcpy(manuf+1, osmocom_magic, sizeof(osmocom_magic)); + break; + default: + return -1; + } + return 0; +} diff --git a/src/osmo-bts-sysmo/utils.h b/src/osmo-bts-sysmo/utils.h index aef774c..85a5e88 100644 --- a/src/osmo-bts-sysmo/utils.h +++ b/src/osmo-bts-sysmo/utils.h @@ -13,4 +13,20 @@ int sysmobts_select_femto_band(struct gsm_bts_trx *trx, uint16_t arfcn); int sysmobts_get_nominal_power(struct gsm_bts_trx *trx); int sysmobts_get_power_trx(struct gsm_bts_trx *trx); + +struct msgb; + +enum manuf_type_id { + IPACCESS_MANUF_ID, + OSMOCOM_MANUF_ID, +}; + +static const char osmocom_magic[] = "org.osmocom"; +static const char ipaccess_magic[] = "com.ipaccess"; + +int add_manufacturer_id_label(struct msgb *msg, int manuf_type_id); + +void prepend_oml_ipa_header(struct msgb *msg); + +int check_oml_msg(struct msgb *msg); #endif -- 1.7.10.4 From anayuso at sysmocom.de Mon May 5 14:14:54 2014 From: anayuso at sysmocom.de (Alvaro Neira Ayuso) Date: Mon, 5 May 2014 16:14:54 +0200 Subject: [osmo-bts PATCH 3/4 v8] misc/sysmomgr: Added Vty support for configuring the manager In-Reply-To: <1397650054-17749-1-git-send-email-anayuso@sysmocom.de> References: <1397650054-17749-1-git-send-email-anayuso@sysmocom.de> Message-ID: <1399299294-15470-1-git-send-email-anayuso@sysmocom.de> Added the vty support for configuring the parameter for using the OML report in manager when we have anomalous temperature. Signed-off-by: Alvaro Neira Ayuso --- doc/examples/osmobts-mgr.cfg | 30 +++ src/osmo-bts-sysmo/Makefile.am | 3 +- src/osmo-bts-sysmo/misc/sysmobts_mgr.c | 43 ++++- src/osmo-bts-sysmo/misc/sysmobts_mgr.h | 18 ++ src/osmo-bts-sysmo/misc/sysmobts_mgr_vty.c | 279 ++++++++++++++++++++++++++++ 5 files changed, 371 insertions(+), 2 deletions(-) create mode 100644 doc/examples/osmobts-mgr.cfg create mode 100644 src/osmo-bts-sysmo/misc/sysmobts_mgr_vty.c diff --git a/doc/examples/osmobts-mgr.cfg b/doc/examples/osmobts-mgr.cfg new file mode 100644 index 0000000..3592202 --- /dev/null +++ b/doc/examples/osmobts-mgr.cfg @@ -0,0 +1,30 @@ +! +! SysmoMgr (0.3.0.141-33e5) configuration saved from vty +!! +! +log stderr + logging filter all 1 + logging color 1 + logging timestamp 0 + logging level all everything + logging level temp info + logging level fw info + logging level find info + logging level lglobal notice + logging level llapd notice + logging level linp notice + logging level lmux notice + logging level lmi notice + logging level lmib notice + logging level lsms notice +! +line vty + no login +! +config-mgr + temperature-warning board -30 50 + temperature-severe board -50 80 + temperature-warning pa -30 50 + temperature-severe pa -50 80 + power-action on on off + power-reduce-transmitter 4 diff --git a/src/osmo-bts-sysmo/Makefile.am b/src/osmo-bts-sysmo/Makefile.am index e9ba949..de70761 100644 --- a/src/osmo-bts-sysmo/Makefile.am +++ b/src/osmo-bts-sysmo/Makefile.am @@ -22,7 +22,8 @@ l1fwd_proxy_LDADD = $(top_builddir)/src/common/libbts.a $(COMMON_LDADD) sysmobts_mgr_SOURCES = \ misc/sysmobts_mgr.c misc/sysmobts_misc.c \ - misc/sysmobts_par.c misc/sysmobts_nl.c utils.c + misc/sysmobts_par.c misc/sysmobts_nl.c utils.c \ + misc/sysmobts_mgr_vty.c sysmobts_mgr_LDADD = $(COMMON_LDADD) sysmobts_util_SOURCES = misc/sysmobts_util.c misc/sysmobts_par.c diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr.c b/src/osmo-bts-sysmo/misc/sysmobts_mgr.c index 51fdd83..99e95d5 100644 --- a/src/osmo-bts-sysmo/misc/sysmobts_mgr.c +++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr.c @@ -52,6 +52,24 @@ static int fd_unix = -1; void *tall_mgr_ctx; static struct sbts2050_config_info confinfo; +static struct sysmobts_mgr_instance sysmobts_mgr_inst = { + .config_file = "osmobts-mgr.cfg", +}; + +const char *sysmomgr_copyright = + "(C) 2012 by Harald Welte \r\n" + "(C) 2014 by Holger Hans Peter Freyther\r\n" + "License AGPLv3+: GNU AGPL version 2 or later \r\n" + "This is free software: you are free to change and redistribute it.\r\n" + "There is NO WARRANTY, to the extent permitted by law.\r\n"; + +static struct vty_app_info vty_info = { + .name = "SysmoMgr", + .version = PACKAGE_VERSION, + .go_parent_cb = mgr_vty_go_parent, + .is_config_node = mgr_vty_is_config_node, +}; + /* every 6 hours means 365*4 = 1460 EEprom writes per year (max) */ #define TEMP_TIMER_SECS (6 * 3600) @@ -221,13 +239,14 @@ static void print_help(void) printf(" -s Disable color\n"); printf(" -d CAT enable debugging\n"); printf(" -D daemonize\n"); + printf(" -c Specify the filename of the config file\n"); } static int parse_options(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "nhsd:")) != -1) { + while ((opt = getopt(argc, argv, "nhsd:c:")) != -1) { switch (opt) { case 'n': no_eeprom_write = 1; @@ -244,6 +263,9 @@ static int parse_options(int argc, char **argv) case 'D': daemonize = 1; break; + case 'c': + sysmobts_mgr_inst.config_file = optarg; + break; default: return -1; } @@ -447,6 +469,25 @@ int main(int argc, char **argv) if (rc < 0) exit(2); + vty_info.copyright = sysmomgr_copyright; + vty_init(&vty_info); + logging_vty_add_cmds(&mgr_log_info); + + sysmobts_mgr_vty_init(); + + rc = sysmobts_mgr_parse_config(sysmobts_mgr_inst.config_file, + &confinfo); + if (rc < 0) { + LOGP(DFIND, LOGL_FATAL, "Cannot parse config file\n"); + exit(1); + } + + rc = telnet_init(tall_msgb_ctx, NULL, 4252); + if (rc < 0) { + fprintf(stderr, "Error initializing telnet\n"); + exit(1); + } + /* start temperature check timer */ temp_timer.cb = check_temp_timer_cb; check_temp_timer_cb(NULL); diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr.h b/src/osmo-bts-sysmo/misc/sysmobts_mgr.h index 21f30a4..5e0d4a7 100644 --- a/src/osmo-bts-sysmo/misc/sysmobts_mgr.h +++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr.h @@ -1,6 +1,9 @@ #ifndef _SYSMOBTS_MGR_H #define _SYSMOBTS_MGR_H +#include +#include + enum { DTEMP, DFW, @@ -14,4 +17,19 @@ enum { #define SOCKET_PATH "/var/run/bts_oml" +struct sbts2050_config_info; + +enum mgr_vty_node { + MGR_NODE = _LAST_OSMOVTY_NODE + 1, +}; + +enum node_type mgr_vty_go_parent(struct vty *vty); +int mgr_vty_is_config_node(struct vty *vty, int node); +int sysmobts_mgr_vty_init(void); +int sysmobts_mgr_parse_config(const char *config_file, + struct sbts2050_config_info *cfg); + +struct sysmobts_mgr_instance { + const char *config_file; +}; #endif diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr_vty.c b/src/osmo-bts-sysmo/misc/sysmobts_mgr_vty.c new file mode 100644 index 0000000..9a77a95 --- /dev/null +++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr_vty.c @@ -0,0 +1,279 @@ +/* (C) 2014 by sysmocom - s.f.m.c. GmbH + * + * All Rights Reserved + * + * Author: Alvaro Neira Ayuso + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "sysmobts_misc.h" +#include "sysmobts_mgr.h" + +static struct sbts2050_config_info *mgr_cfg; + +enum node_type mgr_vty_go_parent(struct vty *vty) +{ + switch (vty->node) { + case MGR_NODE: + vty->node = CONFIG_NODE; + break; + default: + vty->node = CONFIG_NODE; + } + return vty->node; +} + +int mgr_vty_is_config_node(struct vty *vty, int node) +{ + switch (node) { + case MGR_NODE: + return 1; + default: + return 0; + } +} + +#define MGR_STR "Configure sysmobts-mgr\n" +#define MGR_TEMP_WARN_STR "Configure the temperature warning limits\n" +#define MGR_TEMP_SEVERE_STR "Configure the temperature severe limits\n" + +static struct cmd_node mgr_node = { + MGR_NODE, + "%s(config-mgr)# ", + 1, +}; + +DEFUN(cfg_mgr, cfg_mgr_cmd, + "config-mgr", + MGR_STR) +{ + vty->node = MGR_NODE; + return CMD_SUCCESS; +} + +DEFUN(show_mgr, show_mgr_cmd, "show mgr", + SHOW_STR "Display information about the mgr") +{ + vty_out(vty, " temperature-warning board Min:%d Max:%d%s", + mgr_cfg->temp_min_board_warn_limit, + mgr_cfg->temp_max_board_warn_limit, + VTY_NEWLINE); + + vty_out(vty, " temperature-severe board Min:%d Max:%d%s", + mgr_cfg->temp_min_board_severe_limit, + mgr_cfg->temp_max_board_severe_limit, + VTY_NEWLINE); + + vty_out(vty, " temperature-warning pa Min:%d Max:%d%s", + mgr_cfg->temp_min_pa_warn_limit, + mgr_cfg->temp_max_pa_warn_limit, + VTY_NEWLINE); + + vty_out(vty, " temperature-severe pa Min:%d Max:%d%s", + mgr_cfg->temp_min_pa_severe_limit, + mgr_cfg->temp_max_pa_severe_limit, + VTY_NEWLINE); + + vty_out(vty, " power-action Master:%s Slave:%s PA:%s%s", + mgr_cfg->master_power_act ? "on" : "off", + mgr_cfg->slave_power_act ? "on" : "off", + mgr_cfg->pa_power_act ? "on" : "off", + VTY_NEWLINE); + + vty_out(vty, " power-reduce-transmitter %d%s", + mgr_cfg->reduce_max_power, + VTY_NEWLINE); + return CMD_SUCCESS; +} + +static int config_write_mgr(struct vty *vty) +{ + vty_out(vty, "config-mgr%s", VTY_NEWLINE); + + vty_out(vty, " temperature-warning board %d %d%s", + mgr_cfg->temp_min_board_warn_limit, + mgr_cfg->temp_max_board_warn_limit, + VTY_NEWLINE); + + vty_out(vty, " temperature-severe board %d %d%s", + mgr_cfg->temp_min_board_severe_limit, + mgr_cfg->temp_max_board_severe_limit, + VTY_NEWLINE); + + vty_out(vty, " temperature-warning pa %d %d%s", + mgr_cfg->temp_min_pa_warn_limit, + mgr_cfg->temp_max_pa_warn_limit, + VTY_NEWLINE); + + vty_out(vty, " temperature-severe pa %d %d%s", + mgr_cfg->temp_min_pa_severe_limit, + mgr_cfg->temp_max_pa_severe_limit, + VTY_NEWLINE); + + vty_out(vty, " power-action %s %s %s%s", + mgr_cfg->master_power_act ? "on" : "off", + mgr_cfg->slave_power_act ? "on" : "off", + mgr_cfg->pa_power_act ? "on" : "off", + VTY_NEWLINE); + + vty_out(vty, " power-reduce-transmitter %d%s", + mgr_cfg->reduce_max_power, + VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN(cfg_mgr_board_temp_warn, cfg_mgr_board_temp_warn_cmd, + "temperature-warning board <-255-255> <-255-255>", + MGR_TEMP_WARN_STR + "Set warning temperature limits on the Board\n" + "Warning temperature low limit on the Board\n" + "Warning temperature high limit on the Board\n") +{ + mgr_cfg->temp_min_board_warn_limit = atoi(argv[0]); + mgr_cfg->temp_max_board_warn_limit = atoi(argv[1]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_mgr_board_temp_sever, cfg_mgr_board_temp_sever_cmd, + "temperature-severe board <-255-255> <-255-255>", + MGR_TEMP_SEVERE_STR + "Set severe temperature limits on the Board\n" + "Severe temperature low limit on the Board\n" + "Severe Temperature high limit on the Board\n") +{ + mgr_cfg->temp_min_board_severe_limit = atoi(argv[0]); + mgr_cfg->temp_max_board_severe_limit = atoi(argv[1]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_mgr_pa_temp_warn, cfg_mgr_pa_temp_warn_cmd, + "temperature-warning pa <-255-255> <-255-255>", + MGR_TEMP_WARN_STR + "Set warning temperature limits on the PA\n" + "Warning temperature low limit on the PA\n" + "Warning temperature high limit on the PA\n") +{ + mgr_cfg->temp_min_pa_warn_limit = atoi(argv[0]); + mgr_cfg->temp_max_pa_warn_limit = atoi(argv[1]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_mgr_pa_temp_sever, cfg_mgr_pa_temp_sever_cmd, + "temperature-severe pa <-255-255> <-255-255>", + MGR_TEMP_SEVERE_STR + "Set severe temperature limits on the Board\n" + "Severe temperature low limit on the PA\n" + "Severe temperature high limit on the PA\n") +{ + mgr_cfg->temp_min_pa_severe_limit = atoi(argv[0]); + mgr_cfg->temp_max_pa_severe_limit = atoi(argv[1]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_mgr_pwr_action, cfg_mgr_pwr_action_cmd, + "power-action (on|off) (on|off) (on|off)", + "Configure which devices we want to turn on/off in several situation\n" + "Turn on the Master\n" + "Turn off the Master\n" + "Turn on the Slave\n" + "Turn off the Slave\n" + "Turn on the PA\n" + "Turn off the PA\n") +{ + if (strcmp(argv[0], "on") == 0) + mgr_cfg->master_power_act = 1; + else if (strcmp(argv[0], "off") == 0) + mgr_cfg->master_power_act = 0; + + if (strcmp(argv[1], "on") == 0) + mgr_cfg->slave_power_act = 1; + else if (strcmp(argv[1], "off") == 0) + mgr_cfg->slave_power_act = 0; + + if (strcmp(argv[2], "on") == 0) + mgr_cfg->pa_power_act = 1; + else if (strcmp(argv[2], "off") == 0) + mgr_cfg->pa_power_act = 0; + + return CMD_SUCCESS; +} + +DEFUN(cfg_mgr_pa_baud_action, cfg_mgr_pa_baud_action_cmd, + "power-reduce-transmitter <0-255>", + "Configure the power that we want to reduce in warning situation\n" + "Power baud transmition that we want to reduce in the PA\n") +{ + mgr_cfg->reduce_max_power = atoi(argv[0]); + + return CMD_SUCCESS; +} + +int sysmobts_mgr_vty_init(void) + +{ + install_element_ve(&show_mgr_cmd); + + install_node(&mgr_node, config_write_mgr); + install_element(CONFIG_NODE, &cfg_mgr_cmd); + vty_install_default(MGR_NODE); + + install_element(MGR_NODE, &cfg_mgr_board_temp_warn_cmd); + install_element(MGR_NODE, &cfg_mgr_board_temp_sever_cmd); + install_element(MGR_NODE, &cfg_mgr_pa_temp_warn_cmd); + install_element(MGR_NODE, &cfg_mgr_pa_temp_sever_cmd); + install_element(MGR_NODE, &cfg_mgr_pwr_action_cmd); + install_element(MGR_NODE, &cfg_mgr_pa_baud_action_cmd); + + return 0; +} + +int sysmobts_mgr_parse_config(const char *config_file, + struct sbts2050_config_info *cfg) +{ + int rc; + + mgr_cfg = cfg; + + rc = vty_read_config_file(config_file, NULL); + if (rc < 0) { + fprintf(stderr, "Failed to parse the config file: '%s'\n", + config_file); + return rc; + } + + return 0; +} -- 1.7.10.4 From holger at freyther.de Thu May 15 20:31:23 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Thu, 15 May 2014 22:31:23 +0200 Subject: [osmo-bts PATCH 3/4 v8] misc/sysmomgr: Added Vty support for configuring the manager In-Reply-To: <1399299294-15470-1-git-send-email-anayuso@sysmocom.de> References: <1397650054-17749-1-git-send-email-anayuso@sysmocom.de> <1399299294-15470-1-git-send-email-anayuso@sysmocom.de> Message-ID: <20140515203123.GC21990@xiaoyu.lan> On Mon, May 05, 2014 at 04:14:54PM +0200, Alvaro Neira Ayuso wrote: > Added the vty support for configuring the parameter for using the > OML report in manager when we have anomalous temperature. Please try to have a more accurate and descriptive commit message here. > + rc = telnet_init(tall_msgb_ctx, NULL, 4252); I just added this to PortNumber wiki pagein OpenBSC From anayuso at sysmocom.de Sat May 17 08:56:07 2014 From: anayuso at sysmocom.de (Alvaro Neira Ayuso) Date: Sat, 17 May 2014 10:56:07 +0200 Subject: [osmo-bts PATCH 2/3 v9] sysmobts-mgr: Added Vty support for configuring it In-Reply-To: <1399299294-15470-1-git-send-email-anayuso@sysmocom.de> References: <1399299294-15470-1-git-send-email-anayuso@sysmocom.de> Message-ID: <1400316967-24270-1-git-send-email-anayuso@sysmocom.de> From: ?lvaro Neira Ayuso This patch allows to configure the warning temperature threshold, the severe temperature threshold of the board and the PA and the actions like the relative value power that we want to reduce to the transmit power and the part that we want to switch off or not Signed-off-by: Alvaro Neira Ayuso --- [changes in v9] * Changed the subject and the patch explanation. doc/examples/osmobts-mgr.cfg | 30 +++ src/osmo-bts-sysmo/Makefile.am | 3 +- src/osmo-bts-sysmo/misc/sysmobts_mgr.c | 43 ++++- src/osmo-bts-sysmo/misc/sysmobts_mgr.h | 18 ++ src/osmo-bts-sysmo/misc/sysmobts_mgr_vty.c | 279 ++++++++++++++++++++++++++++ 5 files changed, 371 insertions(+), 2 deletions(-) create mode 100644 doc/examples/osmobts-mgr.cfg create mode 100644 src/osmo-bts-sysmo/misc/sysmobts_mgr_vty.c diff --git a/doc/examples/osmobts-mgr.cfg b/doc/examples/osmobts-mgr.cfg new file mode 100644 index 0000000..3592202 --- /dev/null +++ b/doc/examples/osmobts-mgr.cfg @@ -0,0 +1,30 @@ +! +! SysmoMgr (0.3.0.141-33e5) configuration saved from vty +!! +! +log stderr + logging filter all 1 + logging color 1 + logging timestamp 0 + logging level all everything + logging level temp info + logging level fw info + logging level find info + logging level lglobal notice + logging level llapd notice + logging level linp notice + logging level lmux notice + logging level lmi notice + logging level lmib notice + logging level lsms notice +! +line vty + no login +! +config-mgr + temperature-warning board -30 50 + temperature-severe board -50 80 + temperature-warning pa -30 50 + temperature-severe pa -50 80 + power-action on on off + power-reduce-transmitter 4 diff --git a/src/osmo-bts-sysmo/Makefile.am b/src/osmo-bts-sysmo/Makefile.am index e9ba949..de70761 100644 --- a/src/osmo-bts-sysmo/Makefile.am +++ b/src/osmo-bts-sysmo/Makefile.am @@ -22,7 +22,8 @@ l1fwd_proxy_LDADD = $(top_builddir)/src/common/libbts.a $(COMMON_LDADD) sysmobts_mgr_SOURCES = \ misc/sysmobts_mgr.c misc/sysmobts_misc.c \ - misc/sysmobts_par.c misc/sysmobts_nl.c utils.c + misc/sysmobts_par.c misc/sysmobts_nl.c utils.c \ + misc/sysmobts_mgr_vty.c sysmobts_mgr_LDADD = $(COMMON_LDADD) sysmobts_util_SOURCES = misc/sysmobts_util.c misc/sysmobts_par.c diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr.c b/src/osmo-bts-sysmo/misc/sysmobts_mgr.c index 3148c7d..e45d41f 100644 --- a/src/osmo-bts-sysmo/misc/sysmobts_mgr.c +++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr.c @@ -51,6 +51,24 @@ static int daemonize = 0; void *tall_mgr_ctx; static struct sbts2050_config_info confinfo; +static struct sysmobts_mgr_instance sysmobts_mgr_inst = { + .config_file = "osmobts-mgr.cfg", +}; + +const char *sysmomgr_copyright = + "(C) 2012 by Harald Welte \r\n" + "(C) 2014 by Holger Hans Peter Freyther\r\n" + "License AGPLv3+: GNU AGPL version 2 or later \r\n" + "This is free software: you are free to change and redistribute it.\r\n" + "There is NO WARRANTY, to the extent permitted by law.\r\n"; + +static struct vty_app_info vty_info = { + .name = "SysmoMgr", + .version = PACKAGE_VERSION, + .go_parent_cb = mgr_vty_go_parent, + .is_config_node = mgr_vty_is_config_node, +}; + /* every 6 hours means 365*4 = 1460 EEprom writes per year (max) */ #define TEMP_TIMER_SECS (6 * 3600) @@ -222,13 +240,14 @@ static void print_help(void) printf(" -s Disable color\n"); printf(" -d CAT enable debugging\n"); printf(" -D daemonize\n"); + printf(" -c Specify the filename of the config file\n"); } static int parse_options(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "nhsd:")) != -1) { + while ((opt = getopt(argc, argv, "nhsd:c:")) != -1) { switch (opt) { case 'n': no_eeprom_write = 1; @@ -245,6 +264,9 @@ static int parse_options(int argc, char **argv) case 'D': daemonize = 1; break; + case 'c': + sysmobts_mgr_inst.config_file = optarg; + break; default: return -1; } @@ -447,6 +469,25 @@ int main(int argc, char **argv) if (rc < 0) exit(2); + vty_info.copyright = sysmomgr_copyright; + vty_init(&vty_info); + logging_vty_add_cmds(&mgr_log_info); + + sysmobts_mgr_vty_init(); + + rc = sysmobts_mgr_parse_config(sysmobts_mgr_inst.config_file, + &confinfo); + if (rc < 0) { + LOGP(DFIND, LOGL_FATAL, "Cannot parse config file\n"); + exit(1); + } + + rc = telnet_init(tall_msgb_ctx, NULL, 4252); + if (rc < 0) { + fprintf(stderr, "Error initializing telnet\n"); + exit(1); + } + /* start temperature check timer */ temp_timer.cb = check_temp_timer_cb; check_temp_timer_cb(NULL); diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr.h b/src/osmo-bts-sysmo/misc/sysmobts_mgr.h index 21f30a4..5e0d4a7 100644 --- a/src/osmo-bts-sysmo/misc/sysmobts_mgr.h +++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr.h @@ -1,6 +1,9 @@ #ifndef _SYSMOBTS_MGR_H #define _SYSMOBTS_MGR_H +#include +#include + enum { DTEMP, DFW, @@ -14,4 +17,19 @@ enum { #define SOCKET_PATH "/var/run/bts_oml" +struct sbts2050_config_info; + +enum mgr_vty_node { + MGR_NODE = _LAST_OSMOVTY_NODE + 1, +}; + +enum node_type mgr_vty_go_parent(struct vty *vty); +int mgr_vty_is_config_node(struct vty *vty, int node); +int sysmobts_mgr_vty_init(void); +int sysmobts_mgr_parse_config(const char *config_file, + struct sbts2050_config_info *cfg); + +struct sysmobts_mgr_instance { + const char *config_file; +}; #endif diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr_vty.c b/src/osmo-bts-sysmo/misc/sysmobts_mgr_vty.c new file mode 100644 index 0000000..9a77a95 --- /dev/null +++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr_vty.c @@ -0,0 +1,279 @@ +/* (C) 2014 by sysmocom - s.f.m.c. GmbH + * + * All Rights Reserved + * + * Author: Alvaro Neira Ayuso + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "sysmobts_misc.h" +#include "sysmobts_mgr.h" + +static struct sbts2050_config_info *mgr_cfg; + +enum node_type mgr_vty_go_parent(struct vty *vty) +{ + switch (vty->node) { + case MGR_NODE: + vty->node = CONFIG_NODE; + break; + default: + vty->node = CONFIG_NODE; + } + return vty->node; +} + +int mgr_vty_is_config_node(struct vty *vty, int node) +{ + switch (node) { + case MGR_NODE: + return 1; + default: + return 0; + } +} + +#define MGR_STR "Configure sysmobts-mgr\n" +#define MGR_TEMP_WARN_STR "Configure the temperature warning limits\n" +#define MGR_TEMP_SEVERE_STR "Configure the temperature severe limits\n" + +static struct cmd_node mgr_node = { + MGR_NODE, + "%s(config-mgr)# ", + 1, +}; + +DEFUN(cfg_mgr, cfg_mgr_cmd, + "config-mgr", + MGR_STR) +{ + vty->node = MGR_NODE; + return CMD_SUCCESS; +} + +DEFUN(show_mgr, show_mgr_cmd, "show mgr", + SHOW_STR "Display information about the mgr") +{ + vty_out(vty, " temperature-warning board Min:%d Max:%d%s", + mgr_cfg->temp_min_board_warn_limit, + mgr_cfg->temp_max_board_warn_limit, + VTY_NEWLINE); + + vty_out(vty, " temperature-severe board Min:%d Max:%d%s", + mgr_cfg->temp_min_board_severe_limit, + mgr_cfg->temp_max_board_severe_limit, + VTY_NEWLINE); + + vty_out(vty, " temperature-warning pa Min:%d Max:%d%s", + mgr_cfg->temp_min_pa_warn_limit, + mgr_cfg->temp_max_pa_warn_limit, + VTY_NEWLINE); + + vty_out(vty, " temperature-severe pa Min:%d Max:%d%s", + mgr_cfg->temp_min_pa_severe_limit, + mgr_cfg->temp_max_pa_severe_limit, + VTY_NEWLINE); + + vty_out(vty, " power-action Master:%s Slave:%s PA:%s%s", + mgr_cfg->master_power_act ? "on" : "off", + mgr_cfg->slave_power_act ? "on" : "off", + mgr_cfg->pa_power_act ? "on" : "off", + VTY_NEWLINE); + + vty_out(vty, " power-reduce-transmitter %d%s", + mgr_cfg->reduce_max_power, + VTY_NEWLINE); + return CMD_SUCCESS; +} + +static int config_write_mgr(struct vty *vty) +{ + vty_out(vty, "config-mgr%s", VTY_NEWLINE); + + vty_out(vty, " temperature-warning board %d %d%s", + mgr_cfg->temp_min_board_warn_limit, + mgr_cfg->temp_max_board_warn_limit, + VTY_NEWLINE); + + vty_out(vty, " temperature-severe board %d %d%s", + mgr_cfg->temp_min_board_severe_limit, + mgr_cfg->temp_max_board_severe_limit, + VTY_NEWLINE); + + vty_out(vty, " temperature-warning pa %d %d%s", + mgr_cfg->temp_min_pa_warn_limit, + mgr_cfg->temp_max_pa_warn_limit, + VTY_NEWLINE); + + vty_out(vty, " temperature-severe pa %d %d%s", + mgr_cfg->temp_min_pa_severe_limit, + mgr_cfg->temp_max_pa_severe_limit, + VTY_NEWLINE); + + vty_out(vty, " power-action %s %s %s%s", + mgr_cfg->master_power_act ? "on" : "off", + mgr_cfg->slave_power_act ? "on" : "off", + mgr_cfg->pa_power_act ? "on" : "off", + VTY_NEWLINE); + + vty_out(vty, " power-reduce-transmitter %d%s", + mgr_cfg->reduce_max_power, + VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN(cfg_mgr_board_temp_warn, cfg_mgr_board_temp_warn_cmd, + "temperature-warning board <-255-255> <-255-255>", + MGR_TEMP_WARN_STR + "Set warning temperature limits on the Board\n" + "Warning temperature low limit on the Board\n" + "Warning temperature high limit on the Board\n") +{ + mgr_cfg->temp_min_board_warn_limit = atoi(argv[0]); + mgr_cfg->temp_max_board_warn_limit = atoi(argv[1]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_mgr_board_temp_sever, cfg_mgr_board_temp_sever_cmd, + "temperature-severe board <-255-255> <-255-255>", + MGR_TEMP_SEVERE_STR + "Set severe temperature limits on the Board\n" + "Severe temperature low limit on the Board\n" + "Severe Temperature high limit on the Board\n") +{ + mgr_cfg->temp_min_board_severe_limit = atoi(argv[0]); + mgr_cfg->temp_max_board_severe_limit = atoi(argv[1]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_mgr_pa_temp_warn, cfg_mgr_pa_temp_warn_cmd, + "temperature-warning pa <-255-255> <-255-255>", + MGR_TEMP_WARN_STR + "Set warning temperature limits on the PA\n" + "Warning temperature low limit on the PA\n" + "Warning temperature high limit on the PA\n") +{ + mgr_cfg->temp_min_pa_warn_limit = atoi(argv[0]); + mgr_cfg->temp_max_pa_warn_limit = atoi(argv[1]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_mgr_pa_temp_sever, cfg_mgr_pa_temp_sever_cmd, + "temperature-severe pa <-255-255> <-255-255>", + MGR_TEMP_SEVERE_STR + "Set severe temperature limits on the Board\n" + "Severe temperature low limit on the PA\n" + "Severe temperature high limit on the PA\n") +{ + mgr_cfg->temp_min_pa_severe_limit = atoi(argv[0]); + mgr_cfg->temp_max_pa_severe_limit = atoi(argv[1]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_mgr_pwr_action, cfg_mgr_pwr_action_cmd, + "power-action (on|off) (on|off) (on|off)", + "Configure which devices we want to turn on/off in several situation\n" + "Turn on the Master\n" + "Turn off the Master\n" + "Turn on the Slave\n" + "Turn off the Slave\n" + "Turn on the PA\n" + "Turn off the PA\n") +{ + if (strcmp(argv[0], "on") == 0) + mgr_cfg->master_power_act = 1; + else if (strcmp(argv[0], "off") == 0) + mgr_cfg->master_power_act = 0; + + if (strcmp(argv[1], "on") == 0) + mgr_cfg->slave_power_act = 1; + else if (strcmp(argv[1], "off") == 0) + mgr_cfg->slave_power_act = 0; + + if (strcmp(argv[2], "on") == 0) + mgr_cfg->pa_power_act = 1; + else if (strcmp(argv[2], "off") == 0) + mgr_cfg->pa_power_act = 0; + + return CMD_SUCCESS; +} + +DEFUN(cfg_mgr_pa_baud_action, cfg_mgr_pa_baud_action_cmd, + "power-reduce-transmitter <0-255>", + "Configure the power that we want to reduce in warning situation\n" + "Power baud transmition that we want to reduce in the PA\n") +{ + mgr_cfg->reduce_max_power = atoi(argv[0]); + + return CMD_SUCCESS; +} + +int sysmobts_mgr_vty_init(void) + +{ + install_element_ve(&show_mgr_cmd); + + install_node(&mgr_node, config_write_mgr); + install_element(CONFIG_NODE, &cfg_mgr_cmd); + vty_install_default(MGR_NODE); + + install_element(MGR_NODE, &cfg_mgr_board_temp_warn_cmd); + install_element(MGR_NODE, &cfg_mgr_board_temp_sever_cmd); + install_element(MGR_NODE, &cfg_mgr_pa_temp_warn_cmd); + install_element(MGR_NODE, &cfg_mgr_pa_temp_sever_cmd); + install_element(MGR_NODE, &cfg_mgr_pwr_action_cmd); + install_element(MGR_NODE, &cfg_mgr_pa_baud_action_cmd); + + return 0; +} + +int sysmobts_mgr_parse_config(const char *config_file, + struct sbts2050_config_info *cfg) +{ + int rc; + + mgr_cfg = cfg; + + rc = vty_read_config_file(config_file, NULL); + if (rc < 0) { + fprintf(stderr, "Failed to parse the config file: '%s'\n", + config_file); + return rc; + } + + return 0; +} -- 1.7.10.4 From anayuso at sysmocom.de Mon May 5 14:22:59 2014 From: anayuso at sysmocom.de (Alvaro Neira Ayuso) Date: Mon, 5 May 2014 16:22:59 +0200 Subject: [osmo-bts PATCH 4/4 v8] main: Added support for changing the power transmitter in sbts2050 In-Reply-To: <1398686488-20113-1-git-send-email-anayuso@sysmocom.de> References: <1398686488-20113-1-git-send-email-anayuso@sysmocom.de> Message-ID: <1399299779-15739-1-git-send-email-anayuso@sysmocom.de> From: ?lvaro Neira Ayuso Added functions for changing the power transmitter in case of we receive a Failure Event report from the manager. The sbts2050 decress the power transmitter with the value that we have configured in the manager. For doing that the manager send a OML message with the power that we want to decress in warning case and too send another OML message for restoring the power transmitter. Signed-off-by: Alvaro Neira Ayuso --- [changes in v8] * Changed the variable NM_ATT_SBTS_REDUCEPOWER to NM_ATT_O_REDUCEPOWER src/osmo-bts-sysmo/main.c | 123 ++++++++++++++++++++++++++++++- src/osmo-bts-sysmo/misc/sysmobts_mgr.c | 32 +++++--- src/osmo-bts-sysmo/misc/sysmobts_mgr.h | 5 ++ src/osmo-bts-sysmo/misc/sysmobts_misc.c | 69 +++++++++++++++++ src/osmo-bts-sysmo/misc/sysmobts_misc.h | 2 + 5 files changed, 220 insertions(+), 11 deletions(-) diff --git a/src/osmo-bts-sysmo/main.c b/src/osmo-bts-sysmo/main.c index acdf6fc..76305be 100644 --- a/src/osmo-bts-sysmo/main.c +++ b/src/osmo-bts-sysmo/main.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -294,10 +295,107 @@ static int write_pid_file(char *procname) return 0; } +#define oml_tlv_parse(dec, buf, len) \ + tlv_parse(dec, &abis_nm_att_tlvdef, buf, len, 0, 0) + +static int send_oml_fom_ack_nack(int fd_unix, struct msgb *old_msg, + uint8_t cause, int is_manuf) +{ + struct abis_om_hdr *old_om = msgb_l2(old_msg); + struct abis_om_fom_hdr *old_foh = msgb_l3(old_msg); + struct msgb *msg; + struct abis_om_fom_hdr *foh; + struct abis_om_hdr *om; + int rc; + + msg = oml_msgb_alloc(); + if (!msg) + return -ENOMEM; + + msg->l3h = msgb_push(msg, sizeof(*foh)); + foh = (struct abis_om_fom_hdr *) msg->l3h; + memcpy(foh, old_foh, sizeof(*foh)); + + if (is_manuf) { + /* length byte, string + 0 termination */ + uint8_t *manuf = msgb_push(msg, 1 + sizeof(osmocom_magic)); + manuf[0] = strlen(osmocom_magic)+1; + memcpy(manuf+1, osmocom_magic, strlen(osmocom_magic)); + } + + msg->l2h = msgb_push(msg, sizeof(*om)); + om = (struct abis_om_hdr *) msg->l2h; + memcpy(om, old_om, sizeof(*om)); + + /* alter message type */ + if (cause) { + LOGP(DOML, LOGL_ERROR, "Sending FOM NACK with cause %s.\n", + abis_nm_nack_cause_name(cause)); + foh->msg_type += 2; /* nack */ + msgb_tv_put(msg, NM_ATT_NACK_CAUSES, cause); + } else { + LOGP(DOML, LOGL_DEBUG, "Sending FOM ACK.\n"); + foh->msg_type++; /* ack */ + } + + prepend_oml_ipa_header(msg); + + rc = send(fd_unix, msg->data, msg->len, 0); + if (rc < 0 || rc != msg->len) { + LOGP(DTEMP, LOGL_ERROR, "Error writting in unix socket\n"); + close(fd_unix); + msgb_free(msg); + return -1; + } + + return rc; +} + +static void update_transmiter_power(struct gsm_bts_trx *trx) +{ + struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); + + if (fl1h->hLayer1) + l1if_set_txpower(fl1h, sysmobts_get_power_trx(trx)); +} + +static int take_reduce_power(struct msgb *msg) +{ + int recv_reduce_power; + struct tlv_parsed tlv_out; + struct gsm_bts_trx *trx = bts->c0; + int rc, abis_oml_hdr_len; + + abis_oml_hdr_len = sizeof(struct abis_om_hdr); + abis_oml_hdr_len += sizeof(struct abis_om_fom_hdr); + abis_oml_hdr_len += sizeof(osmocom_magic) + 1; + + rc = oml_tlv_parse(&tlv_out, msg->data + abis_oml_hdr_len, + msg->len - abis_oml_hdr_len); + + if (rc < 0) { + msgb_free(msg); + return -1; + } + + if (TLVP_PRESENT(&tlv_out, NM_ATT_O_REDUCEPOWER)) + recv_reduce_power = *TLVP_VAL(&tlv_out, + NM_ATT_O_REDUCEPOWER); + else + return -1; + + trx->power_reduce = recv_reduce_power; + + update_transmiter_power(trx); + + return 0; +} + static int read_sock(struct osmo_fd *fd, unsigned int what) { struct msgb *msg; struct gsm_abis_mo *mo; + struct abis_om_fom_hdr *fom; int rc; msg = oml_msgb_alloc(); @@ -323,9 +421,32 @@ static int read_sock(struct osmo_fd *fd, unsigned int what) mo = &bts->mo; msg->trx = mo->bts->c0; + fom = (struct abis_om_fom_hdr *) msg->l3h; - return abis_oml_sendmsg(msg); + switch (fom->msg_type) { + case NM_MT_SET_RADIO_ATTR: + rc = take_reduce_power(msg); + if (rc < 0) { + rc = send_oml_fom_ack_nack(fd->fd, msg, + NM_NACK_INCORR_STRUCT, 1); + } else { + rc = send_oml_fom_ack_nack(fd->fd, msg, 0, 1); + } + msgb_free(msg); + break; + case NM_MT_FAILURE_EVENT_REP: + rc = abis_oml_sendmsg(msg); + break; + default: + LOGP(DL1C, LOGL_ERROR, "Unknown Fom message type %d\n", + fom->msg_type); + goto err; + } + if (rc < 0) + goto err; + + return rc; err: msgb_free(msg); return -1; diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr.c b/src/osmo-bts-sysmo/misc/sysmobts_mgr.c index 99e95d5..bb9bcac 100644 --- a/src/osmo-bts-sysmo/misc/sysmobts_mgr.c +++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr.c @@ -82,6 +82,7 @@ static struct vty_app_info vty_info = { #ifdef BUILD_SBTS2050 static int trx_nr = -1; static int state_connection; +static int status_change_power_red; static struct osmo_timer_list connect_timer; static void socket_connect_cb(void *data) @@ -138,17 +139,18 @@ static void check_uctemp_timer_cb(void *data) { int temp_pa = 0, temp_board = 0; struct uc *ucontrol0 = data; + int pa_warning, board_warning; sbts2050_uc_check_temp(ucontrol0, &temp_pa, &temp_board); confinfo.temp_pa_cur = temp_pa; confinfo.temp_board_cur = temp_board; - check_temperature(ucontrol0, - confinfo.temp_min_pa_warn_limit, - confinfo.temp_max_pa_warn_limit, - temp_pa, SBTS2050_TEMP_PA, - SBTS2050_WARN_ALERT); + pa_warning = check_temperature(ucontrol0, + confinfo.temp_min_pa_warn_limit, + confinfo.temp_max_pa_warn_limit, + temp_pa, SBTS2050_TEMP_PA, + SBTS2050_WARN_ALERT); check_temperature(ucontrol0, confinfo.temp_min_pa_severe_limit, @@ -156,11 +158,11 @@ static void check_uctemp_timer_cb(void *data) temp_pa, SBTS2050_TEMP_PA, SBTS2050_SEVERE_ALERT); - check_temperature(ucontrol0, - confinfo.temp_min_board_warn_limit, - confinfo.temp_max_board_warn_limit, - temp_board, SBTS2050_TEMP_BOARD, - SBTS2050_WARN_ALERT); + board_warning = check_temperature(ucontrol0, + confinfo.temp_min_board_warn_limit, + confinfo.temp_max_board_warn_limit, + temp_board, SBTS2050_TEMP_BOARD, + SBTS2050_WARN_ALERT); check_temperature(ucontrol0, confinfo.temp_min_board_severe_limit, @@ -168,6 +170,16 @@ static void check_uctemp_timer_cb(void *data) temp_board, SBTS2050_TEMP_BOARD, SBTS2050_SEVERE_ALERT); + if ((pa_warning || board_warning) && + status_change_power_red == SBTS2050_DISABLE_CHANGE_POWER) { + status_change_power_red = SBTS2050_ENABLE_CHANGE_POWER; + send_omlreduce(fd_unix, confinfo.reduce_max_power, trx_nr); + } else if (!pa_warning && !board_warning && + status_change_power_red == SBTS2050_ENABLE_CHANGE_POWER) { + status_change_power_red = SBTS2050_DISABLE_CHANGE_POWER; + send_omlreduce(fd_unix, 0, trx_nr); + } + osmo_timer_schedule(&temp_uc_timer, TEMP_TIMER_SECS, 0); } #endif diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr.h b/src/osmo-bts-sysmo/misc/sysmobts_mgr.h index 5e0d4a7..026afd5 100644 --- a/src/osmo-bts-sysmo/misc/sysmobts_mgr.h +++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr.h @@ -15,6 +15,11 @@ enum { SYSMO_MGR_CONNECTED, }; +enum { + SBTS2050_DISABLE_CHANGE_POWER = 0, + SBTS2050_ENABLE_CHANGE_POWER, +}; + #define SOCKET_PATH "/var/run/bts_oml" struct sbts2050_config_info; diff --git a/src/osmo-bts-sysmo/misc/sysmobts_misc.c b/src/osmo-bts-sysmo/misc/sysmobts_misc.c index 2030888..14b2985 100644 --- a/src/osmo-bts-sysmo/misc/sysmobts_misc.c +++ b/src/osmo-bts-sysmo/misc/sysmobts_misc.c @@ -58,6 +58,23 @@ #define OM_HEADROOM_SIZE 128 #ifdef BUILD_SBTS2050 + +static int check_omlreduce_nach_ack(struct msgb *msg) +{ + struct abis_om_fom_hdr *foh = msgb_l3(msg); + + if (foh->msg_type == NM_MT_SET_RADIO_ATTR + 2) { /* NACK */ + LOGP(DTEMP, LOGL_ERROR, "Reduce Power: Received a BTS NACK\n"); + return -1; + } else if (foh->msg_type != NM_MT_SET_RADIO_ATTR + 1) { /* ACK */ + LOGP(DTEMP, LOGL_ERROR, "Unknown message type %d\n", + foh->msg_type); + return -1; + } + + return 0; +} + static void add_sw_descr(struct msgb *msg) { char file_version[255]; @@ -116,6 +133,58 @@ static void add_oml_hdr_msg(struct msgb *msg, uint8_t msg_type, omh->length = msgb_l3len(msg); } +int send_omlreduce(int fd_unix, int reduce_power, int trx_nr) +{ + int rc; + struct msgb *msg; + + msg = msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE, "OML"); + if (msg == NULL) { + LOGP(DTEMP, LOGL_ERROR, "Error creating oml msg\n"); + return -1; + } + + add_oml_hdr_msg(msg, NM_MT_SET_RADIO_ATTR, 2, 0, trx_nr, 255, 1); + + msgb_tv_put(msg, NM_ATT_O_REDUCEPOWER, reduce_power); + + prepend_oml_ipa_header(msg); + + rc = send(fd_unix, msg->data, msg->len, 0); + if (rc < 0 || rc != msg->len) { + LOGP(DTEMP, LOGL_ERROR, "Error writting to unix socket\n"); + goto err; + } + + msgb_reset(msg); + rc = recv(fd_unix, msg->tail, msg->data_len, 0); + if (rc <= 0) { + LOGP(DTEMP, LOGL_ERROR, "Error reading from unix socket\n"); + goto err; + } + msgb_put(msg, rc); + + if (check_oml_msg(msg) < 0) { + close(fd_unix); + msgb_free(msg); + return -1; + } + + if (check_omlreduce_nach_ack(msg) < 0) { + close(fd_unix); + msgb_free(msg); + return -1; + } + + msgb_free(msg); + return SYSMO_MGR_CONNECTED; + +err: + close(fd_unix); + msgb_free(msg); + return SYSMO_MGR_DISCONNECTED; +} + int send_omlfailure(int fd_unix, enum sbts2050_alert_lvl alert, enum sbts2050_temp_sensor sensor, struct sbts2050_config_info *add_info, int trx_nr) diff --git a/src/osmo-bts-sysmo/misc/sysmobts_misc.h b/src/osmo-bts-sysmo/misc/sysmobts_misc.h index c22a54b..158e7a2 100644 --- a/src/osmo-bts-sysmo/misc/sysmobts_misc.h +++ b/src/osmo-bts-sysmo/misc/sysmobts_misc.h @@ -75,6 +75,8 @@ int send_omlfailure(int fd_unix, enum sbts2050_alert_lvl alert, enum sbts2050_temp_sensor sensor, struct sbts2050_config_info *add_info, int trx_nr); +int send_omlreduce(int fd_unix, int reduce_power, int trx_nr); + int sysmobts_update_hours(int no_epprom_write); enum sysmobts_firmware_type { -- 1.7.10.4 From holger at freyther.de Thu May 15 20:47:18 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Thu, 15 May 2014 22:47:18 +0200 Subject: [osmo-bts PATCH 4/4 v8] main: Added support for changing the power transmitter in sbts2050 In-Reply-To: <1399299779-15739-1-git-send-email-anayuso@sysmocom.de> References: <1398686488-20113-1-git-send-email-anayuso@sysmocom.de> <1399299779-15739-1-git-send-email-anayuso@sysmocom.de> Message-ID: <20140515204718.GD21990@xiaoyu.lan> On Mon, May 05, 2014 at 04:22:59PM +0200, Alvaro Neira Ayuso wrote: > From: ?lvaro Neira Ayuso > > Added functions for changing the power transmitter in case of we receive transmit power? > a Failure Event report from the manager. The sbts2050 decress the This is not what happens. Is it? The manager will ask for the power being reduced. It is not related to a OML Failure Event report. decress.. do you mean decrease? > power transmitter with the value that we have configured in the manager. > + if (is_manuf) { > + /* length byte, string + 0 termination */ > + uint8_t *manuf = msgb_push(msg, 1 + sizeof(osmocom_magic)); > + manuf[0] = strlen(osmocom_magic)+1; > + memcpy(manuf+1, osmocom_magic, strlen(osmocom_magic)); > + } Same as in the other mail. Maybe even share this with a function to put the osmocom manufacturer header. > + prepend_oml_ipa_header(msg); > + > + rc = send(fd_unix, msg->data, msg->len, 0); > + if (rc < 0 || rc != msg->len) { > + LOGP(DTEMP, LOGL_ERROR, "Error writting in unix socket\n"); > + close(fd_unix); > + msgb_free(msg); > + return -1; > + } > + > + return rc; Are you leaking the msgb here? I think I saw similar code in the previous patch. For previous leaks I asked you to send the messages in a loop to make it obvious that some meoyr is leaked.. > + if ((pa_warning || board_warning) && > + status_change_power_red == SBTS2050_DISABLE_CHANGE_POWER) { > + status_change_power_red = SBTS2050_ENABLE_CHANGE_POWER; > + send_omlreduce(fd_unix, confinfo.reduce_max_power, trx_nr); > + } else if (!pa_warning && !board_warning && > + status_change_power_red == SBTS2050_ENABLE_CHANGE_POWER) { > + status_change_power_red = SBTS2050_DISABLE_CHANGE_POWER; > + send_omlreduce(fd_unix, 0, trx_nr); > + } Move this into a method. We certainly will change the code in the future to not just go from 0 to X for power changes. The method should take pa_warning, board_warning, the state and it should return -1 if no change is required and otherwise the power it should be reduced to. > + rc = recv(fd_unix, msg->tail, msg->data_len, 0); > + if (rc <= 0) { > + LOGP(DTEMP, LOGL_ERROR, "Error reading from unix socket\n"); print the kind of error like in the error log messages. From anayuso at sysmocom.de Sat May 17 09:01:13 2014 From: anayuso at sysmocom.de (Alvaro Neira Ayuso) Date: Sat, 17 May 2014 11:01:13 +0200 Subject: [osmo-bts PATCH 3/3 v9] sysmobts: Add support for changing the transmit power in sbts2050 In-Reply-To: <1399299779-15739-1-git-send-email-anayuso@sysmocom.de> References: <1399299779-15739-1-git-send-email-anayuso@sysmocom.de> Message-ID: <1400317273-24414-1-git-send-email-anayuso@sysmocom.de> From: ?lvaro Neira Ayuso Make the sysmobts-mgr sends a manufacturer O&M message with the relative value that we want to reduce in the sysmobts. The sysmobts receives this messages. Messages passing a sanity check takes the relative value that we want to reduce and the sysmobts reduces the transmit power. The sysmobts-mgr receives a ACK/NACK for knowing that the transmit power has been updated. Signed-off-by: Alvaro Neira Ayuso --- [changes in v9] * Removed the code for adding the manufacturer ID label and used the new function inside utils. * Removed leak when we send the ack/nack when we receive the reduce manufacturer O&M message and it has passed a sanity check. * Moved the code when we check if the PA or the Board is under a temperature warning situation and when we send the relative value that we want to use for reduce the transmit power to a new function for make easy future changes. * Changed some log messages for adding more util information for debugging. src/osmo-bts-sysmo/main.c | 122 ++++++++++++++++++++++++++++++- src/osmo-bts-sysmo/misc/sysmobts_mgr.c | 41 ++++++++--- src/osmo-bts-sysmo/misc/sysmobts_mgr.h | 5 ++ src/osmo-bts-sysmo/misc/sysmobts_misc.c | 72 ++++++++++++++++++ src/osmo-bts-sysmo/misc/sysmobts_misc.h | 2 + 5 files changed, 231 insertions(+), 11 deletions(-) diff --git a/src/osmo-bts-sysmo/main.c b/src/osmo-bts-sysmo/main.c index bd6a181..2c13a9c 100644 --- a/src/osmo-bts-sysmo/main.c +++ b/src/osmo-bts-sysmo/main.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -294,10 +295,106 @@ static int write_pid_file(char *procname) return 0; } +#define oml_tlv_parse(dec, buf, len) \ + tlv_parse(dec, &abis_nm_att_tlvdef, buf, len, 0, 0) + +static int send_oml_fom_ack_nack(int fd_unix, struct msgb *old_msg, + uint8_t cause, int is_manuf) +{ + struct abis_om_hdr *old_om = msgb_l2(old_msg); + struct abis_om_fom_hdr *old_foh = msgb_l3(old_msg); + struct msgb *msg; + struct abis_om_fom_hdr *foh; + struct abis_om_hdr *om; + int rc; + + msg = oml_msgb_alloc(); + if (!msg) + return -ENOMEM; + + msg->l3h = msgb_push(msg, sizeof(*foh)); + foh = (struct abis_om_fom_hdr *) msg->l3h; + memcpy(foh, old_foh, sizeof(*foh)); + + if (is_manuf) + add_manufacturer_id_label(msg, OSMOCOM_MANUF_ID); + + msg->l2h = msgb_push(msg, sizeof(*om)); + om = (struct abis_om_hdr *) msg->l2h; + memcpy(om, old_om, sizeof(*om)); + + /* alter message type */ + if (cause) { + LOGP(DOML, LOGL_ERROR, "Sending FOM NACK with cause %s.\n", + abis_nm_nack_cause_name(cause)); + foh->msg_type += 2; /* nack */ + msgb_tv_put(msg, NM_ATT_NACK_CAUSES, cause); + } else { + LOGP(DOML, LOGL_DEBUG, "Sending FOM ACK.\n"); + foh->msg_type++; /* ack */ + } + + prepend_oml_ipa_header(msg); + + rc = send(fd_unix, msg->data, msg->len, 0); + if (rc < 0 || rc != msg->len) { + LOGP(DTEMP, LOGL_ERROR, + "send error %s during ACK/NACK message send\n", + strerror(errno)); + close(fd_unix); + msgb_free(msg); + return -1; + } + + msgb_free(msg); + return rc; +} + +static void update_transmiter_power(struct gsm_bts_trx *trx) +{ + struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); + + if (fl1h->hLayer1) + l1if_set_txpower(fl1h, sysmobts_get_power_trx(trx)); +} + +static int take_reduce_power(struct msgb *msg) +{ + int recv_reduce_power; + struct tlv_parsed tlv_out; + struct gsm_bts_trx *trx = bts->c0; + int rc, abis_oml_hdr_len; + + abis_oml_hdr_len = sizeof(struct abis_om_hdr); + abis_oml_hdr_len += sizeof(struct abis_om_fom_hdr); + abis_oml_hdr_len += sizeof(osmocom_magic) + 1; + + rc = oml_tlv_parse(&tlv_out, msg->data + abis_oml_hdr_len, + msg->len - abis_oml_hdr_len); + + if (rc < 0) { + msgb_free(msg); + return -1; + } + + if (TLVP_PRESENT(&tlv_out, NM_ATT_O_REDUCEPOWER)) + recv_reduce_power = *TLVP_VAL(&tlv_out, + NM_ATT_O_REDUCEPOWER); + else + return -1; + + trx->power_reduce = recv_reduce_power; + + update_transmiter_power(trx); + + return 0; +} + static int read_sock(struct osmo_fd *fd, unsigned int what) { struct msgb *msg; struct gsm_abis_mo *mo; + struct abis_om_fom_hdr *fom; int rc; msg = oml_msgb_alloc(); @@ -324,9 +421,32 @@ static int read_sock(struct osmo_fd *fd, unsigned int what) mo = &bts->mo; msg->trx = mo->bts->c0; + fom = (struct abis_om_fom_hdr *) msg->l3h; - return abis_oml_sendmsg(msg); + switch (fom->msg_type) { + case NM_MT_SET_RADIO_ATTR: + rc = take_reduce_power(msg); + if (rc < 0) { + rc = send_oml_fom_ack_nack(fd->fd, msg, + NM_NACK_INCORR_STRUCT, 1); + } else { + rc = send_oml_fom_ack_nack(fd->fd, msg, 0, 1); + } + msgb_free(msg); + break; + case NM_MT_FAILURE_EVENT_REP: + rc = abis_oml_sendmsg(msg); + break; + default: + LOGP(DL1C, LOGL_ERROR, "Unknown Fom message type %d\n", + fom->msg_type); + goto err; + } + if (rc < 0) + goto err; + + return rc; err: msgb_free(msg); return -1; diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr.c b/src/osmo-bts-sysmo/misc/sysmobts_mgr.c index e45d41f..4aa2cbf 100644 --- a/src/osmo-bts-sysmo/misc/sysmobts_mgr.c +++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr.c @@ -82,6 +82,7 @@ static struct vty_app_info vty_info = { static int fd_unix = -1; static int trx_nr = -1; static int state_connection; +static int status_change_power_red; static struct osmo_timer_list temp_uc_timer; static struct osmo_timer_list connect_timer; @@ -135,21 +136,39 @@ static int check_temperature(struct uc *ucontrol0, int lowlimit, int highlimit, return 1; } +static int check_warning_state(int pa_warning, int board_warning) +{ + if ((pa_warning || board_warning) && + status_change_power_red == SBTS2050_DISABLE_CHANGE_POWER) { + status_change_power_red = SBTS2050_ENABLE_CHANGE_POWER; + send_manufacturer_reduce_msg(fd_unix, confinfo.reduce_max_power, + trx_nr); + } else if (!pa_warning && !board_warning && + status_change_power_red == SBTS2050_ENABLE_CHANGE_POWER) { + status_change_power_red = SBTS2050_DISABLE_CHANGE_POWER; + send_manufacturer_reduce_msg(fd_unix, 0, trx_nr); + } else + return -1; + + return 0; +} + static void check_uctemp_timer_cb(void *data) { int temp_pa = 0, temp_board = 0; struct uc *ucontrol0 = data; + int pa_warning, board_warning; sbts2050_uc_check_temp(ucontrol0, &temp_pa, &temp_board); confinfo.temp_pa_cur = temp_pa; confinfo.temp_board_cur = temp_board; - check_temperature(ucontrol0, - confinfo.temp_min_pa_warn_limit, - confinfo.temp_max_pa_warn_limit, - temp_pa, SBTS2050_TEMP_PA, - SBTS2050_WARN_ALERT); + pa_warning = check_temperature(ucontrol0, + confinfo.temp_min_pa_warn_limit, + confinfo.temp_max_pa_warn_limit, + temp_pa, SBTS2050_TEMP_PA, + SBTS2050_WARN_ALERT); check_temperature(ucontrol0, confinfo.temp_min_pa_severe_limit, @@ -157,11 +176,11 @@ static void check_uctemp_timer_cb(void *data) temp_pa, SBTS2050_TEMP_PA, SBTS2050_SEVERE_ALERT); - check_temperature(ucontrol0, - confinfo.temp_min_board_warn_limit, - confinfo.temp_max_board_warn_limit, - temp_board, SBTS2050_TEMP_BOARD, - SBTS2050_WARN_ALERT); + board_warning = check_temperature(ucontrol0, + confinfo.temp_min_board_warn_limit, + confinfo.temp_max_board_warn_limit, + temp_board, SBTS2050_TEMP_BOARD, + SBTS2050_WARN_ALERT); check_temperature(ucontrol0, confinfo.temp_min_board_severe_limit, @@ -169,6 +188,8 @@ static void check_uctemp_timer_cb(void *data) temp_board, SBTS2050_TEMP_BOARD, SBTS2050_SEVERE_ALERT); + check_warning_state(pa_warning, board_warning); + osmo_timer_schedule(&temp_uc_timer, TEMP_TIMER_SECS, 0); } #endif diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr.h b/src/osmo-bts-sysmo/misc/sysmobts_mgr.h index 5e0d4a7..026afd5 100644 --- a/src/osmo-bts-sysmo/misc/sysmobts_mgr.h +++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr.h @@ -15,6 +15,11 @@ enum { SYSMO_MGR_CONNECTED, }; +enum { + SBTS2050_DISABLE_CHANGE_POWER = 0, + SBTS2050_ENABLE_CHANGE_POWER, +}; + #define SOCKET_PATH "/var/run/bts_oml" struct sbts2050_config_info; diff --git a/src/osmo-bts-sysmo/misc/sysmobts_misc.c b/src/osmo-bts-sysmo/misc/sysmobts_misc.c index 2417c3d..6277a6b 100644 --- a/src/osmo-bts-sysmo/misc/sysmobts_misc.c +++ b/src/osmo-bts-sysmo/misc/sysmobts_misc.c @@ -58,6 +58,23 @@ #define OM_HEADROOM_SIZE 128 #ifdef BUILD_SBTS2050 + +static int check_manufacturer_reduce_nach_ack(struct msgb *msg) +{ + struct abis_om_fom_hdr *foh = msgb_l3(msg); + + if (foh->msg_type == NM_MT_SET_RADIO_ATTR + 2) { /* NACK */ + LOGP(DTEMP, LOGL_ERROR, "Reduce Power: Received a BTS NACK\n"); + return -1; + } else if (foh->msg_type != NM_MT_SET_RADIO_ATTR + 1) { /* ACK */ + LOGP(DTEMP, LOGL_ERROR, "Unknown message type %d\n", + foh->msg_type); + return -1; + } + + return 0; +} + static void add_sw_descr(struct msgb *msg) { char file_version[255]; @@ -112,6 +129,61 @@ static void add_oml_hdr_msg(struct msgb *msg, uint8_t msg_type, omh->length = msgb_l3len(msg); } +int send_manufacturer_reduce_msg(int fd_unix, int reduce_power, int trx_nr) +{ + int rc; + struct msgb *msg; + + msg = msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE, "OML"); + if (msg == NULL) { + LOGP(DTEMP, LOGL_ERROR, "Error creating oml msg\n"); + return -1; + } + + add_oml_hdr_msg(msg, NM_MT_SET_RADIO_ATTR, 2, 0, trx_nr, 255, 1); + + msgb_tv_put(msg, NM_ATT_O_REDUCEPOWER, reduce_power); + + prepend_oml_ipa_header(msg); + + rc = send(fd_unix, msg->data, msg->len, 0); + if (rc < 0 || rc != msg->len) { + LOGP(DTEMP, LOGL_ERROR, + "send error %s during Reduce Manufacturer O&M msg send\n", + strerror(errno)); + goto err; + } + + msgb_reset(msg); + rc = recv(fd_unix, msg->tail, msg->data_len, 0); + if (rc <= 0) { + LOGP(DTEMP, LOGL_ERROR, "recv error %s during ACK/NACK recv\n", + strerror(errno)); + goto err; + } + msgb_put(msg, rc); + + if (check_oml_msg(msg) < 0) { + close(fd_unix); + msgb_free(msg); + return -1; + } + + if (check_manufacturer_reduce_nach_ack(msg) < 0) { + close(fd_unix); + msgb_free(msg); + return -1; + } + + msgb_free(msg); + return SYSMO_MGR_CONNECTED; + +err: + close(fd_unix); + msgb_free(msg); + return SYSMO_MGR_DISCONNECTED; +} + int send_omlfailure(int fd_unix, enum sbts2050_alert_lvl alert, enum sbts2050_temp_sensor sensor, struct sbts2050_config_info *add_info, int trx_nr) diff --git a/src/osmo-bts-sysmo/misc/sysmobts_misc.h b/src/osmo-bts-sysmo/misc/sysmobts_misc.h index c22a54b..740ce2d 100644 --- a/src/osmo-bts-sysmo/misc/sysmobts_misc.h +++ b/src/osmo-bts-sysmo/misc/sysmobts_misc.h @@ -75,6 +75,8 @@ int send_omlfailure(int fd_unix, enum sbts2050_alert_lvl alert, enum sbts2050_temp_sensor sensor, struct sbts2050_config_info *add_info, int trx_nr); +int send_manufacturer_reduce_msg(int fd_unix, int reduce_power, int trx_nr); + int sysmobts_update_hours(int no_epprom_write); enum sysmobts_firmware_type { -- 1.7.10.4 From anayuso at sysmocom.de Tue May 20 05:50:48 2014 From: anayuso at sysmocom.de (Alvaro Neira Ayuso) Date: Tue, 20 May 2014 07:50:48 +0200 Subject: [osmo-bts PATCH 5/5 v10] main: Added support for changing the max_power_red in sbts2050 In-Reply-To: <1400317273-24414-1-git-send-email-anayuso@sysmocom.de> References: <1400317273-24414-1-git-send-email-anayuso@sysmocom.de> Message-ID: <1400565048-11164-1-git-send-email-anayuso@sysmocom.de> From: ?lvaro Neira Ayuso Make the sysmobts-mgr sends a manufacturer O&M message with the relative value that we want to reduce in the sysmobts. The sysmobts receives this messages. Messages passing a sanity check takes the relative value that we want to reduce and the sysmobts reduces the transmit power. The sysmobts-mgr receives a ACK/NACK for knowing that the transmit power has been updated. Signed-off-by: Alvaro Neira Ayuso --- [changes in v10] * Changed the variable NM_ATT_O_REDUCEPOWER to NM_ATT_OSMO_REDUCEPOWER. * Changed abis_nm_att_tlvdef to abis_nm_osmo_att_tlvdef for parsing the the osmocom attributes * Changed the function take_reduce_power for using abis_om_fom_hdr and the len of the l3h and not the message. * Checked if the message that we have checked is the type that we expect. * Used the new function for doing the sanity check to the ipa header and later the oml message src/osmo-bts-sysmo/main.c | 128 ++++++++++++++++++++++++++++++- src/osmo-bts-sysmo/misc/sysmobts_mgr.c | 41 +++++++--- src/osmo-bts-sysmo/misc/sysmobts_mgr.h | 5 ++ src/osmo-bts-sysmo/misc/sysmobts_misc.c | 80 +++++++++++++++++++ src/osmo-bts-sysmo/misc/sysmobts_misc.h | 2 + 5 files changed, 245 insertions(+), 11 deletions(-) diff --git a/src/osmo-bts-sysmo/main.c b/src/osmo-bts-sysmo/main.c index 797f174..ec3ea78 100644 --- a/src/osmo-bts-sysmo/main.c +++ b/src/osmo-bts-sysmo/main.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -294,10 +295,100 @@ static int write_pid_file(char *procname) return 0; } +#define oml_tlv_parse(dec, buf, len) \ + tlv_parse(dec, &abis_nm_osmo_att_tlvdef, buf, len, 0, 0) + +static int send_oml_fom_ack_nack(int fd_unix, struct msgb *old_msg, + uint8_t cause, int is_manuf) +{ + struct abis_om_hdr *old_om = msgb_l2(old_msg); + struct abis_om_fom_hdr *old_foh = msgb_l3(old_msg); + struct msgb *msg; + struct abis_om_fom_hdr *foh; + struct abis_om_hdr *om; + int rc; + + msg = oml_msgb_alloc(); + if (!msg) + return -ENOMEM; + + msg->l3h = msgb_push(msg, sizeof(*foh)); + foh = (struct abis_om_fom_hdr *) msg->l3h; + memcpy(foh, old_foh, sizeof(*foh)); + + if (is_manuf) + add_manufacturer_id_label(msg, OSMOCOM_MANUF_ID); + + msg->l2h = msgb_push(msg, sizeof(*om)); + om = (struct abis_om_hdr *) msg->l2h; + memcpy(om, old_om, sizeof(*om)); + + /* alter message type */ + if (cause) { + LOGP(DOML, LOGL_ERROR, "Sending FOM NACK with cause %s.\n", + abis_nm_nack_cause_name(cause)); + foh->msg_type += 2; /* nack */ + msgb_tv_put(msg, NM_ATT_NACK_CAUSES, cause); + } else { + LOGP(DOML, LOGL_DEBUG, "Sending FOM ACK.\n"); + foh->msg_type++; /* ack */ + } + + prepend_oml_ipa_header(msg); + + rc = send(fd_unix, msg->data, msg->len, 0); + if (rc < 0 || rc != msg->len) { + LOGP(DTEMP, LOGL_ERROR, + "send error %s during ACK/NACK message send\n", + strerror(errno)); + close(fd_unix); + msgb_free(msg); + return -1; + } + + msgb_free(msg); + return rc; +} + +static void update_transmiter_power(struct gsm_bts_trx *trx) +{ + struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); + + if (fl1h->hLayer1) + l1if_set_txpower(fl1h, sysmobts_get_power_trx(trx)); +} + +static int take_reduce_power(struct abis_om_fom_hdr *fom, int len) +{ + int recv_reduce_power; + struct tlv_parsed tlv_out; + struct gsm_bts_trx *trx = bts->c0; + int rc; + + rc = oml_tlv_parse(&tlv_out, fom->data, + len - sizeof(struct abis_om_fom_hdr)); + + if (rc < 0) + return -1; + + if (TLVP_PRESENT(&tlv_out, NM_ATT_OSMO_REDUCEPOWER)) + recv_reduce_power = *TLVP_VAL(&tlv_out, + NM_ATT_OSMO_REDUCEPOWER); + else + return -1; + + trx->power_reduce = recv_reduce_power; + + update_transmiter_power(trx); + + return 0; +} + static int read_sock(struct osmo_fd *fd, unsigned int what) { struct msgb *msg; struct gsm_abis_mo *mo; + struct abis_om_fom_hdr *fom; int rc; msg = oml_msgb_alloc(); @@ -333,9 +424,44 @@ static int read_sock(struct osmo_fd *fd, unsigned int what) mo = &bts->mo; msg->trx = mo->bts->c0; + fom = (struct abis_om_fom_hdr *) msg->l3h; + + switch (fom->msg_type) { + case NM_MT_SET_RADIO_ATTR: + if (rc == MANUFACTURER_MSG_OSMO_TYPE) + rc = take_reduce_power(fom, msgb_l3len(msg)); + else { + LOGP(DL1C, LOGL_ERROR, "Incorrect message type %d\n", + rc); + rc = -1; + } + if (rc < 0) { + rc = send_oml_fom_ack_nack(fd->fd, msg, + NM_NACK_INCORR_STRUCT, 1); + } else { + rc = send_oml_fom_ack_nack(fd->fd, msg, 0, 1); + } + msgb_free(msg); + break; + case NM_MT_FAILURE_EVENT_REP: + if (rc == OML_MSG_TYPE) + rc = abis_oml_sendmsg(msg); + else { + LOGP(DL1C, LOGL_ERROR, "Incorrect message type %d\n", + rc); + rc = -1; + } + break; + default: + LOGP(DL1C, LOGL_ERROR, "Unknown Fom message type %d\n", + fom->msg_type); + goto err; + } - return abis_oml_sendmsg(msg); + if (rc < 0) + goto err; + return rc; err: msgb_free(msg); return -1; diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr.c b/src/osmo-bts-sysmo/misc/sysmobts_mgr.c index e45d41f..4aa2cbf 100644 --- a/src/osmo-bts-sysmo/misc/sysmobts_mgr.c +++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr.c @@ -82,6 +82,7 @@ static struct vty_app_info vty_info = { static int fd_unix = -1; static int trx_nr = -1; static int state_connection; +static int status_change_power_red; static struct osmo_timer_list temp_uc_timer; static struct osmo_timer_list connect_timer; @@ -135,21 +136,39 @@ static int check_temperature(struct uc *ucontrol0, int lowlimit, int highlimit, return 1; } +static int check_warning_state(int pa_warning, int board_warning) +{ + if ((pa_warning || board_warning) && + status_change_power_red == SBTS2050_DISABLE_CHANGE_POWER) { + status_change_power_red = SBTS2050_ENABLE_CHANGE_POWER; + send_manufacturer_reduce_msg(fd_unix, confinfo.reduce_max_power, + trx_nr); + } else if (!pa_warning && !board_warning && + status_change_power_red == SBTS2050_ENABLE_CHANGE_POWER) { + status_change_power_red = SBTS2050_DISABLE_CHANGE_POWER; + send_manufacturer_reduce_msg(fd_unix, 0, trx_nr); + } else + return -1; + + return 0; +} + static void check_uctemp_timer_cb(void *data) { int temp_pa = 0, temp_board = 0; struct uc *ucontrol0 = data; + int pa_warning, board_warning; sbts2050_uc_check_temp(ucontrol0, &temp_pa, &temp_board); confinfo.temp_pa_cur = temp_pa; confinfo.temp_board_cur = temp_board; - check_temperature(ucontrol0, - confinfo.temp_min_pa_warn_limit, - confinfo.temp_max_pa_warn_limit, - temp_pa, SBTS2050_TEMP_PA, - SBTS2050_WARN_ALERT); + pa_warning = check_temperature(ucontrol0, + confinfo.temp_min_pa_warn_limit, + confinfo.temp_max_pa_warn_limit, + temp_pa, SBTS2050_TEMP_PA, + SBTS2050_WARN_ALERT); check_temperature(ucontrol0, confinfo.temp_min_pa_severe_limit, @@ -157,11 +176,11 @@ static void check_uctemp_timer_cb(void *data) temp_pa, SBTS2050_TEMP_PA, SBTS2050_SEVERE_ALERT); - check_temperature(ucontrol0, - confinfo.temp_min_board_warn_limit, - confinfo.temp_max_board_warn_limit, - temp_board, SBTS2050_TEMP_BOARD, - SBTS2050_WARN_ALERT); + board_warning = check_temperature(ucontrol0, + confinfo.temp_min_board_warn_limit, + confinfo.temp_max_board_warn_limit, + temp_board, SBTS2050_TEMP_BOARD, + SBTS2050_WARN_ALERT); check_temperature(ucontrol0, confinfo.temp_min_board_severe_limit, @@ -169,6 +188,8 @@ static void check_uctemp_timer_cb(void *data) temp_board, SBTS2050_TEMP_BOARD, SBTS2050_SEVERE_ALERT); + check_warning_state(pa_warning, board_warning); + osmo_timer_schedule(&temp_uc_timer, TEMP_TIMER_SECS, 0); } #endif diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr.h b/src/osmo-bts-sysmo/misc/sysmobts_mgr.h index 5e0d4a7..026afd5 100644 --- a/src/osmo-bts-sysmo/misc/sysmobts_mgr.h +++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr.h @@ -15,6 +15,11 @@ enum { SYSMO_MGR_CONNECTED, }; +enum { + SBTS2050_DISABLE_CHANGE_POWER = 0, + SBTS2050_ENABLE_CHANGE_POWER, +}; + #define SOCKET_PATH "/var/run/bts_oml" struct sbts2050_config_info; diff --git a/src/osmo-bts-sysmo/misc/sysmobts_misc.c b/src/osmo-bts-sysmo/misc/sysmobts_misc.c index 2417c3d..4f08cfd 100644 --- a/src/osmo-bts-sysmo/misc/sysmobts_misc.c +++ b/src/osmo-bts-sysmo/misc/sysmobts_misc.c @@ -58,6 +58,23 @@ #define OM_HEADROOM_SIZE 128 #ifdef BUILD_SBTS2050 + +static int check_manufacturer_reduce_nach_ack(struct msgb *msg) +{ + struct abis_om_fom_hdr *foh = msgb_l3(msg); + + if (foh->msg_type == NM_MT_SET_RADIO_ATTR + 2) { /* NACK */ + LOGP(DTEMP, LOGL_ERROR, "Reduce Power: Received a BTS NACK\n"); + return -1; + } else if (foh->msg_type != NM_MT_SET_RADIO_ATTR + 1) { /* ACK */ + LOGP(DTEMP, LOGL_ERROR, "Unknown message type %d\n", + foh->msg_type); + return -1; + } + + return 0; +} + static void add_sw_descr(struct msgb *msg) { char file_version[255]; @@ -112,6 +129,69 @@ static void add_oml_hdr_msg(struct msgb *msg, uint8_t msg_type, omh->length = msgb_l3len(msg); } +int send_manufacturer_reduce_msg(int fd_unix, int reduce_power, int trx_nr) +{ + int rc; + struct msgb *msg; + + msg = msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE, "OML"); + if (msg == NULL) { + LOGP(DTEMP, LOGL_ERROR, "Error creating oml msg\n"); + return -1; + } + + add_oml_hdr_msg(msg, NM_MT_SET_RADIO_ATTR, 2, 0, trx_nr, 255, 1); + + msgb_tv_put(msg, NM_ATT_OSMO_REDUCEPOWER, reduce_power); + + prepend_oml_ipa_header(msg); + + rc = send(fd_unix, msg->data, msg->len, 0); + if (rc < 0 || rc != msg->len) { + LOGP(DTEMP, LOGL_ERROR, + "send error %s during Reduce Manufacturer O&M msg send\n", + strerror(errno)); + goto err; + } + + msgb_reset(msg); + rc = recv(fd_unix, msg->tail, msg->data_len, 0); + if (rc <= 0) { + LOGP(DTEMP, LOGL_ERROR, "recv error %s during ACK/NACK recv\n", + strerror(errno)); + goto err; + } + msgb_put(msg, rc); + + if (check_ipa_header(msg) < 0) { + close(fd_unix); + msgb_free(msg); + return -1; + } + + msgb_pull(msg, sizeof(struct ipaccess_head)); + + if (check_oml_msg(msg) < 0) { + close(fd_unix); + msgb_free(msg); + return -1; + } + + if (check_manufacturer_reduce_nach_ack(msg) < 0) { + close(fd_unix); + msgb_free(msg); + return -1; + } + + msgb_free(msg); + return SYSMO_MGR_CONNECTED; + +err: + close(fd_unix); + msgb_free(msg); + return SYSMO_MGR_DISCONNECTED; +} + int send_omlfailure(int fd_unix, enum sbts2050_alert_lvl alert, enum sbts2050_temp_sensor sensor, struct sbts2050_config_info *add_info, int trx_nr) diff --git a/src/osmo-bts-sysmo/misc/sysmobts_misc.h b/src/osmo-bts-sysmo/misc/sysmobts_misc.h index c22a54b..740ce2d 100644 --- a/src/osmo-bts-sysmo/misc/sysmobts_misc.h +++ b/src/osmo-bts-sysmo/misc/sysmobts_misc.h @@ -75,6 +75,8 @@ int send_omlfailure(int fd_unix, enum sbts2050_alert_lvl alert, enum sbts2050_temp_sensor sensor, struct sbts2050_config_info *add_info, int trx_nr); +int send_manufacturer_reduce_msg(int fd_unix, int reduce_power, int trx_nr); + int sysmobts_update_hours(int no_epprom_write); enum sysmobts_firmware_type { -- 1.7.10.4 From holger at freyther.de Tue May 20 07:05:36 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Tue, 20 May 2014 09:05:36 +0200 Subject: [osmo-bts PATCH 5/5 v10] main: Added support for changing the max_power_red in sbts2050 In-Reply-To: <1400565048-11164-1-git-send-email-anayuso@sysmocom.de> References: <1400317273-24414-1-git-send-email-anayuso@sysmocom.de> <1400565048-11164-1-git-send-email-anayuso@sysmocom.de> Message-ID: <20140520070536.GP29651@xiaoyu.lan> On Tue, May 20, 2014 at 07:50:48AM +0200, Alvaro Neira Ayuso wrote: > From: ?lvaro Neira Ayuso > > Make the sysmobts-mgr sends a manufacturer O&M message > with the relative value that we want to reduce in the > sysmobts. The sysmobts receives this messages. Messages > passing a sanity check takes the relative value that we > want to reduce and the sysmobts reduces the transmit > power. The sysmobts-mgr receives a ACK/NACK for knowing > that the transmit power has been updated. Where is this coming from? I think it is an old/partially updated patch? From alvaroneay at gmail.com Tue May 20 07:40:35 2014 From: alvaroneay at gmail.com (=?ISO-8859-1?Q?=C1lvaro_Neira_Ayuso?=) Date: Tue, 20 May 2014 09:40:35 +0200 Subject: [osmo-bts PATCH 5/5 v10] main: Added support for changing the max_power_red in sbts2050 In-Reply-To: <20140520070536.GP29651@xiaoyu.lan> References: <1400317273-24414-1-git-send-email-anayuso@sysmocom.de> <1400565048-11164-1-git-send-email-anayuso@sysmocom.de> <20140520070536.GP29651@xiaoyu.lan> Message-ID: <537B06F3.2040504@gmail.com> Hello Holger El 20/05/14 09:05, Holger Hans Peter Freyther escribi?: > On Tue, May 20, 2014 at 07:50:48AM +0200, Alvaro Neira Ayuso wrote: >> From: ?lvaro Neira Ayuso >> >> Make the sysmobts-mgr sends a manufacturer O&M message >> with the relative value that we want to reduce in the >> sysmobts. The sysmobts receives this messages. Messages >> passing a sanity check takes the relative value that we >> want to reduce and the sysmobts reduces the transmit >> power. The sysmobts-mgr receives a ACK/NACK for knowing >> that the transmit power has been updated. > > Where is this coming from? I think it is an old/partially > updated patch? Yes, this is a old/partially updated patch with the new functions that I have done in utils and using the new variable of the patch 430c771244ae37d7cd95960fc1781ed6aeed1213, Fix introducing osmocom speficic OML attributes. That patch was reverted for updating it. Regards ?lvaro From holger at freyther.de Tue May 20 07:52:12 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Tue, 20 May 2014 09:52:12 +0200 Subject: [osmo-bts PATCH 5/5 v10] main: Added support for changing the max_power_red in sbts2050 In-Reply-To: <537B06F3.2040504@gmail.com> References: <1400317273-24414-1-git-send-email-anayuso@sysmocom.de> <1400565048-11164-1-git-send-email-anayuso@sysmocom.de> <20140520070536.GP29651@xiaoyu.lan> <537B06F3.2040504@gmail.com> Message-ID: <20140520075212.GA2910@xiaoyu.lan> On Tue, May 20, 2014 at 09:40:35AM +0200, ?lvaro Neira Ayuso wrote: Hi, > Yes, this is a old/partially updated patch with the new functions that I > have done in utils and using the new variable of the patch > 430c771244ae37d7cd95960fc1781ed6aeed1213, Fix introducing osmocom speficic > OML attributes. That patch was reverted for updating it. ah right. Harald reverted the patch. I didn't notice that yesterday. From holger at freyther.de Tue May 20 08:05:42 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Tue, 20 May 2014 10:05:42 +0200 Subject: [osmo-bts PATCH 5/5 v10] main: Added support for changing the max_power_red in sbts2050 In-Reply-To: <1400565048-11164-1-git-send-email-anayuso@sysmocom.de> References: <1400317273-24414-1-git-send-email-anayuso@sysmocom.de> <1400565048-11164-1-git-send-email-anayuso@sysmocom.de> Message-ID: <20140520080542.GB2910@xiaoyu.lan> On Tue, May 20, 2014 at 07:50:48AM +0200, Alvaro Neira Ayuso wrote: > +static int send_oml_fom_ack_nack(int fd_unix, struct msgb *old_msg, > + uint8_t cause, int is_manuf) > +{ Separate this method into several ones. * You have modeled oml_fom_ack_nack and instead of copying it you should extend oml_fom_ack_nack to support your use case. The differences are: ** Support com.ipacces and org.osmocom manufacturer type ** Be able to send the message through a different socket. The first can be achieved by modifying the parameter in oml_send_msg to get the manufacturer name that can be put. E.g. by having the cstring. The later can be done by separating message creation and sending. Please do the re-work like this. And create seaprate patches for the refactoring. > +static int take_reduce_power(struct abis_om_fom_hdr *fom, int len) > +{ > + rc = oml_tlv_parse(&tlv_out, fom->data, > + len - sizeof(struct abis_om_fom_hdr)); plese use sizeof(*fom) P From laforge at gnumonks.org Mon May 19 10:02:12 2014 From: laforge at gnumonks.org (Harald Welte) Date: Mon, 19 May 2014 12:02:12 +0200 Subject: [osmo-bts PATCH 3/3] main: Added support for changing the max_power_red in sbts2050 In-Reply-To: <1396960835-14662-1-git-send-email-anayuso@sysmocom.de> References: <1396960835-14662-1-git-send-email-anayuso@sysmocom.de> Message-ID: <20140519100212.GW14533@nataraja> Hi Alvaro, On Tue, Apr 08, 2014 at 02:40:35PM +0200, Alvaro Neira Ayuso wrote: > +#define oml_tlv_parse(dec, buf, len) \ > + tlv_parse(dec, &abis_nm_att_tlvdef, buf, len, 0, 0) by doing so, you are using abis_nm_att_tlvdef, which is defining 0x01 as NM_ATT_ABIS_CHANNEL, which is a fixed-size attribute of 3 bytes length. That's quite something else than what you need, isn't it? I've introduced abis_nm_att_osmo_tlvdef[] in libosmocore. Please either use tlv_def_patch() to merge abis_nm_att_osmo_tlvdef with abis_nm_att_tlvdef before calling tlv_parse from generic code. Or, if you are sure that only a org.osmocom specific message can arrive, you may use abis_nm_att_osmo_tlvdef directly. > +static int take_reduce_power(struct msgb *msg) this function takes the msgb pointer, even though from where it is called in read_sock(): + fom = (struct abis_om_fom_hdr *) msg->l3h; + switch (fom->msg_type) { + case NM_MT_SET_RADIO_ATTR: + rc = take_reduce_power(msg); we already had computed the exact location of 'fom'. Now in take_reduce_power, you do the following: +static int take_reduce_power(struct msgb *msg) +{ + int recv_reduce_power; + struct tlv_parsed tlv_out; + struct gsm_bts_trx *trx = bts->c0; + int rc, abis_oml_hdr_len; + + abis_oml_hdr_len = sizeof(struct abis_om_hdr); + abis_oml_hdr_len += sizeof(struct abis_om_fom_hdr); + abis_oml_hdr_len += sizeof(osmocom_magic) + 1; so you basically make blind assumptions that there is na osmocom_magic and its associated length. However, the check_oml_msg() that you wrote accepts both the com.ipaccess and the org.osmocom magic values. So a) a com.ipaccess message might end up in take_reduce_power() b) your static assumption that an osmocom magic being present is not true. Please properly think about such logic. It might be best if the check_oml_message or similar would return some information (or even store it in the msgb_cb() somewhere) which of the vendor specific messages (if any) it has detected. Later code could then base its processing on that distinction. Also, as you had already resolved the fom pointer (from msg->l3,), thre is no point in starting to calculate abis_oml_hdr_len again (and wrongly). Finally, regarding check_oml_msg(): It actually doedn't only check an OML message, but it checks also the IPA headre in front. Please create one function for one purpose. The check_oml_msg() shouldn't care about the ipaccess_head in front. If we make it more generic, we can move it to libosmocore as a general OML header sanity checking function. But that's not possible right now as it depends on an ipaccess_head, which is not present in E1 based OML. Also, +int add_manufacturer_id_label(struct msgb *msg, int manuf_type_id) why use an int there? You have defined an 'enum manuf_type_id', please use it :) Regards, Harald -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From tom at tsou.cc Thu May 1 17:51:41 2014 From: tom at tsou.cc (Tom Tsou) Date: Thu, 1 May 2014 13:51:41 -0400 Subject: [PATCH 1/4] core/conv: Add optimized Viterbi decoding In-Reply-To: <20140429070845.GD3544@xiaoyu.lan> References: <20140429041209.GA5135@phenom.hsd1.va.comcast.net> <20140429070845.GD3544@xiaoyu.lan> Message-ID: On Tue, Apr 29, 2014 at 3:08 AM, Holger Hans Peter Freyther wrote: > On Tue, Apr 29, 2014 at 12:12:09AM -0400, Thomas Tsou wrote: >> +#define SSE_ALIGN 16 >> + >> +static int16_t *vdec_malloc(size_t n) >> +{ >> +#ifdef HAVE_SSE3 >> + return (int16_t *) memalign(SSE_ALIGN, sizeof(int16_t) * n); >> +#else >> + return (int16_t *) malloc(sizeof(int16_t) * n); >> +#endif >> +} > > argh, it would be nice if you could use talloc here but then we would > need to play games and align pointers ourselves. Maybe change the API > to at least have a 'ctx' similar to other talloc API? A beneficial change would be to modify the API to allow persistent decoder objects instead of performing an allocation and tear-down on every decoding call. From a performance standpoint, the current implementation is unnecessarily restricted by memory access and page faults for that reason. >> +static void free_trellis(struct vtrellis *trellis) >> +{ >> + if (!trellis) >> + return; >> + >> + free(trellis->vals); >> + free(trellis->outputs); >> + free(trellis->sums); >> + free(trellis); > > Can you use talloc here? Yes. I think that makes sense. Memory alignment is the only issue that needs to be looked into. >> + _traceback_rec(dec, state, out, len); > > _ is reserved for the system. We might want to avoid using that. I thought only double underscore and single underscore with capital letter were reserved? -TT From jerlbeck at sysmocom.de Thu May 8 08:06:38 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Thu, 08 May 2014 10:06:38 +0200 Subject: [PATCH 1/4] core/conv: Add optimized Viterbi decoding In-Reply-To: References: <20140429041209.GA5135@phenom.hsd1.va.comcast.net> <20140429070845.GD3544@xiaoyu.lan> Message-ID: <536B3B0E.1070403@sysmocom.de> On 01.05.2014 19:51, Tom Tsou wrote: > > A beneficial change would be to modify the API to allow persistent > decoder objects instead of performing an allocation and tear-down on > every decoding call. From a performance standpoint, the current > implementation is unnecessarily restricted by memory access and page > faults for that reason. I'd appreciate that very much, since I'm planning to port it to the epiphany where I definitely want neither to malloc nor to talloc. Jacob From 246tnt at gmail.com Wed May 7 16:25:11 2014 From: 246tnt at gmail.com (Sylvain Munaut) Date: Wed, 7 May 2014 18:25:11 +0200 Subject: [PATCH 1/4] core/conv: Add optimized Viterbi decoding In-Reply-To: <20140429041209.GA5135@phenom.hsd1.va.comcast.net> References: <20140429041209.GA5135@phenom.hsd1.va.comcast.net> Message-ID: Hi Thomas, I've just only seen this. I'll try to test and comment on them ASAP. Some quick things I saw from a quick glance though: - Some things that should be 'static' are not and they pollute the global namespace - Anything that is in the global namespace needs the osmo_ (or even osmo_conv_ here) prefix - Did you check (and test in make test) that it works for all codes that matches "if ((code->N <= 4) && ((code->K == 5) || (code->K == 7)))" ? - The viterbi_gen file seems fairly easy to generate, maybe in the future it'd be worth autogenerating it Also, to avoid exporting those internal symbols, I'm wondering if #including the viterbi_gen.c from viterbi.c instead of compiling separately wouldn't be better. But that's just a random idea ... > A beneficial change would be to modify the API to allow persistent > decoder objects instead of performing an allocation and tear-down on > every decoding call. From a performance standpoint, the current > implementation is unnecessarily restricted by memory access and page > faults for that reason. You can't change the existing API without breaking existing stuff, but you can add a new all-in-one function that allows to give a persistent decoder object. like osmo_conv_decode_persist or whatever you want to call it. Cheers, Sylvain On Tue, Apr 29, 2014 at 6:12 AM, Thomas Tsou wrote: > Add a separate, faster convolution decoding implementation for rates > up to N=4 and constraint lengths of K=5 and K=7, which covers the > most GSM code uses. The decoding algorithm exploits the symmetric > structure of the Viterbi add-compare-select (ACS) operation - commonly > known as the ACS butterfly. This shift-register optimization can be > found in the well-known text by Dave Forney. > > Forney, G.D., "The Viterbi Algorithm," Proc. of the IEEE, March 1973. > > Implementation is non-architecture specific and improves performance on > x86 as well as ARM processors. Existing API is unchanged with optimized > code being called internally for supported codes. > > Signed-off-by: Thomas Tsou > --- > src/Makefile.am | 3 +- > src/conv.c | 9 + > src/viterbi.c | 603 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ > src/viterbi_gen.c | 182 ++++++++++++++++ > 4 files changed, 796 insertions(+), 1 deletion(-) > create mode 100644 src/viterbi.c > create mode 100644 src/viterbi_gen.c > > diff --git a/src/Makefile.am b/src/Makefile.am > index e68c29a..262a4e6 100644 > --- a/src/Makefile.am > +++ b/src/Makefile.am > @@ -13,7 +13,8 @@ libosmocore_la_SOURCES = timer.c select.c signal.c msgb.c bits.c \ > logging.c logging_syslog.c rate_ctr.c \ > gsmtap_util.c crc16.c panic.c backtrace.c \ > conv.c application.c rbtree.c strrb.c \ > - loggingrb.c crc8gen.c crc16gen.c crc32gen.c crc64gen.c > + loggingrb.c crc8gen.c crc16gen.c crc32gen.c crc64gen.c \ > + viterbi.c viterbi_gen.c > > BUILT_SOURCES = crc8gen.c crc16gen.c crc32gen.c crc64gen.c > > diff --git a/src/conv.c b/src/conv.c > index f13deef..79b3a7c 100644 > --- a/src/conv.c > +++ b/src/conv.c > @@ -238,6 +238,11 @@ osmo_conv_encode(const struct osmo_conv_code *code, > > #define MAX_AE 0x00ffffff > > +/* Forward declaration for accerlated decoding with certain codes */ > +int > +osmo_conv_decode_acc(const struct osmo_conv_code *code, > + const sbit_t *input, ubit_t *output); > + > void > osmo_conv_decode_init(struct osmo_conv_decoder *decoder, > const struct osmo_conv_code *code, int len, int start_state) > @@ -606,6 +611,10 @@ osmo_conv_decode(const struct osmo_conv_code *code, > struct osmo_conv_decoder decoder; > int rv, l; > > + /* Use accelerated implementation for supported codes */ > + if ((code->N <= 4) && ((code->K == 5) || (code->K == 7))) > + return osmo_conv_decode_acc(code, input, output); > + > osmo_conv_decode_init(&decoder, code, 0, 0); > > if (code->term == CONV_TERM_TAIL_BITING) { > diff --git a/src/viterbi.c b/src/viterbi.c > new file mode 100644 > index 0000000..db8d5c8 > --- /dev/null > +++ b/src/viterbi.c > @@ -0,0 +1,603 @@ > +/* > + * Viterbi decoder > + * Copyright (C) 2013, 2014 Thomas Tsou > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA > + */ > + > +#include "config.h" > + > +#include > +#include > +#include > +#include > +#include > + > +/* Forward Metric Units */ > +void gen_metrics_k5_n2(const int8_t *seq, const int16_t *out, > + int16_t *sums, int16_t *paths, int norm); > +void gen_metrics_k5_n3(const int8_t *seq, const int16_t *out, > + int16_t *sums, int16_t *paths, int norm); > +void gen_metrics_k5_n4(const int8_t *seq, const int16_t *out, > + int16_t *sums, int16_t *paths, int norm); > +void gen_metrics_k7_n2(const int8_t *seq, const int16_t *out, > + int16_t *sums, int16_t *paths, int norm); > +void gen_metrics_k7_n3(const int8_t *seq, const int16_t *out, > + int16_t *sums, int16_t *paths, int norm); > +void gen_metrics_k7_n4(const int8_t *seq, const int16_t *out, > + int16_t *sums, int16_t *paths, int norm); > +/* Trellis State > + * state - Internal lshift register value > + * prev - Register values of previous 0 and 1 states > + */ > +struct vstate { > + unsigned state; > + unsigned prev[2]; > +}; > + > +/* Trellis Object > + * num_states - Number of states in the trellis > + * sums - Accumulated path metrics > + * outputs - Trellis ouput values > + * vals - Input value that led to each state > + */ > +struct vtrellis { > + int num_states; > + int16_t *sums; > + int16_t *outputs; > + uint8_t *vals; > +}; > + > +/* Viterbi Decoder > + * n - Code order > + * k - Constraint length > + * len - Horizontal length of trellis > + * recursive - Set to '1' if the code is recursive > + * intrvl - Normalization interval > + * trellis - Trellis object > + * punc - Puncturing sequence > + * paths - Trellis paths > + */ > +struct vdecoder { > + int n; > + int k; > + int len; > + int recursive; > + int intrvl; > + struct vtrellis *trellis; > + int *punc; > + int16_t **paths; > + > + void (*metric_func)(const int8_t *, const int16_t *, > + int16_t *, int16_t *, int); > +}; > + > +/* Aligned Memory Allocator > + * SSE requires 16-byte memory alignment. We store relevant trellis values > + * (accumulated sums, outputs, and path decisions) as 16 bit signed integers > + * so the allocated memory is casted as such. > + */ > +#define SSE_ALIGN 16 > + > +static int16_t *vdec_malloc(size_t n) > +{ > +#ifdef HAVE_SSE3 > + return (int16_t *) memalign(SSE_ALIGN, sizeof(int16_t) * n); > +#else > + return (int16_t *) malloc(sizeof(int16_t) * n); > +#endif > +} > + > +/* Accessor calls */ > +inline int conv_code_recursive(const struct osmo_conv_code *code) > +{ > + return code->next_term_output ? 1 : 0; > +} > + > +/* Left shift and mask for finding the previous state */ > +static unsigned vstate_lshift(unsigned reg, int k, int val) > +{ > + unsigned mask; > + > + if (k == 5) > + mask = 0x0e; > + else if (k == 7) > + mask = 0x3e; > + else > + mask = 0; > + > + return ((reg << 1) & mask) | val; > +} > + > +/* Bit endian manipulators */ > +inline unsigned bitswap2(unsigned v) > +{ > + return ((v & 0x02) >> 1) | ((v & 0x01) << 1); > +} > + > +inline unsigned bitswap3(unsigned v) > +{ > + return ((v & 0x04) >> 2) | ((v & 0x02) >> 0) | > + ((v & 0x01) << 2); > +} > + > +inline unsigned bitswap4(unsigned v) > +{ > + return ((v & 0x08) >> 3) | ((v & 0x04) >> 1) | > + ((v & 0x02) << 1) | ((v & 0x01) << 3); > +} > + > +inline unsigned bitswap5(unsigned v) > +{ > + return ((v & 0x10) >> 4) | ((v & 0x08) >> 2) | ((v & 0x04) >> 0) | > + ((v & 0x02) << 2) | ((v & 0x01) << 4); > +} > + > +inline unsigned bitswap6(unsigned v) > +{ > + return ((v & 0x20) >> 5) | ((v & 0x10) >> 3) | ((v & 0x08) >> 1) | > + ((v & 0x04) << 1) | ((v & 0x02) << 3) | ((v & 0x01) << 5); > +} > + > +static unsigned bitswap(unsigned v, unsigned n) > +{ > + switch (n) { > + case 1: > + return v; > + case 2: > + return bitswap2(v); > + case 3: > + return bitswap3(v); > + case 4: > + return bitswap4(v); > + case 5: > + return bitswap5(v); > + case 6: > + return bitswap6(v); > + default: > + break; > + } > + > + return 0; > +} > + > +/* Generate non-recursive state output from generator state table > + * Note that the shift register moves right (i.e. the most recent bit is > + * shifted into the register at k-1 bit of the register), which is typical > + * textbook representation. The API transition table expects the most recent > + * bit in the low order bit, or left shift. A bitswap operation is required > + * to accommodate the difference. > + */ > +static unsigned gen_output(struct vstate *state, int val, > + const struct osmo_conv_code *code) > +{ > + unsigned out, prev; > + > + prev = bitswap(state->prev[0], code->K - 1); > + out = code->next_output[prev][val]; > + out = bitswap(out, code->N); > + > + return out; > +} > + > +#define BIT2NRZ(REG,N) (((REG >> N) & 0x01) * 2 - 1) * -1 > + > +/* Populate non-recursive trellis state > + * For a given state defined by the k-1 length shift register, find the > + * value of the input bit that drove the trellis to that state. Also > + * generate the N outputs of the generator polynomial at that state. > + */ > +static int gen_state_info(uint8_t *val, unsigned reg, > + int16_t *output, const struct osmo_conv_code *code) > +{ > + int i; > + unsigned out; > + struct vstate state; > + > + /* Previous '0' state */ > + state.state = reg; > + state.prev[0] = vstate_lshift(reg, code->K, 0); > + state.prev[1] = vstate_lshift(reg, code->K, 1); > + > + *val = (reg >> (code->K - 2)) & 0x01; > + > + /* Transition output */ > + out = gen_output(&state, *val, code); > + > + /* Unpack to NRZ */ > + for (i = 0; i < code->N; i++) > + output[i] = BIT2NRZ(out, i); > + > + return 0; > +} > + > +/* Generate recursive state output from generator state table */ > +static unsigned gen_recursive_output(struct vstate *state, > + uint8_t *val, unsigned reg, > + const struct osmo_conv_code *code, int pos) > +{ > + int val0, val1; > + unsigned out, prev; > + > + /* Previous '0' state */ > + prev = vstate_lshift(reg, code->K, 0); > + prev = bitswap(prev, code->K - 1); > + > + /* Input value */ > + val0 = (reg >> (code->K - 2)) & 0x01; > + val1 = (code->next_term_output[prev] >> pos) & 0x01; > + *val = val0 == val1 ? 0 : 1; > + > + /* Wrapper for osmocom state access */ > + prev = bitswap(state->prev[0], code->K - 1); > + > + /* Compute the transition output */ > + out = code->next_output[prev][*val]; > + out = bitswap(out, code->N); > + > + return out; > +} > + > +#define NUM_STATES(K) (K == 7 ? 64 : 16) > + > +/* Populate recursive trellis state > + * The bit position of the systematic bit is not explicitly marked by the > + * API, so it must be extracted from the generator table. Otherwise, > + * populate the trellis similar to the non-recursive version. > + * Non-systematic recursive codes are not supported. > + */ > +static int gen_recursive_state_info(uint8_t *val, > + unsigned reg, > + int16_t *output, > + const struct osmo_conv_code *code) > +{ > + int i, j, pos = -1; > + int ns = NUM_STATES(code->K); > + unsigned out; > + struct vstate state; > + > + /* Previous '0' and '1' states */ > + state.state = reg; > + state.prev[0] = vstate_lshift(reg, code->K, 0); > + state.prev[1] = vstate_lshift(reg, code->K, 1); > + > + /* Find recursive bit location */ > + for (i = 0; i < code->N; i++) { > + for (j = 0; j < ns; j++) { > + if ((code->next_output[j][0] >> i) & 0x01) > + break; > + } > + if (j == ns) { > + pos = i; > + break; > + } > + } > + > + /* Non-systematic recursive code not supported */ > + if (pos < 0) > + return -EPROTO; > + > + /* Transition output */ > + out = gen_recursive_output(&state, val, reg, code, pos); > + > + /* Unpack to NRZ */ > + for (i = 0; i < code->N; i++) > + output[i] = BIT2NRZ(out, i); > + > + return 0; > +} > + > +/* Release the trellis */ > +static void free_trellis(struct vtrellis *trellis) > +{ > + if (!trellis) > + return; > + > + free(trellis->vals); > + free(trellis->outputs); > + free(trellis->sums); > + free(trellis); > +} > + > +/* Allocate and initialize the trellis object > + * Initialization consists of generating the outputs and output value of a > + * given state. Due to trellis symmetry and anti-symmetry, only one of the > + * transition paths is utilized by the butterfly operation in the forward > + * recursion, so only one set of N outputs is required per state variable. > + */ > +static struct vtrellis *generate_trellis(const struct osmo_conv_code *code) > +{ > + int i, rc = -1; > + struct vtrellis *trellis; > + int16_t *outputs; > + > + int ns = NUM_STATES(code->K); > + int recursive = conv_code_recursive(code); > + int olen = (code->N == 2) ? 2 : 4; > + > + trellis = (struct vtrellis *) calloc(1, sizeof(struct vtrellis)); > + trellis->num_states = ns; > + trellis->sums = vdec_malloc(ns); > + trellis->outputs = vdec_malloc(ns * olen); > + trellis->vals = (uint8_t *) malloc(ns * sizeof(uint8_t)); > + > + if (!trellis->sums || !trellis->outputs) > + goto fail; > + > + /* Populate the trellis state objects */ > + for (i = 0; i < ns; i++) { > + outputs = &trellis->outputs[olen * i]; > + > + if (recursive) > + rc = gen_recursive_state_info(&trellis->vals[i], > + i, outputs, code); > + else > + rc = gen_state_info(&trellis->vals[i], > + i, outputs, code); > + } > + > + if (rc < 0) > + goto fail; > + > + return trellis; > +fail: > + free_trellis(trellis); > + return NULL; > +} > + > +/* Reset decoder > + * Set accumulated path metrics to zero. For termination other than > + * tail-biting, initialize the zero state as the encoder starting state. > + * Intialize with the maximum accumulated sum at length equal to the > + * constraint length. > + */ > +static void reset_decoder(struct vdecoder *dec, int term) > +{ > + int ns = dec->trellis->num_states; > + > + memset(dec->trellis->sums, 0, sizeof(int16_t) * ns); > + > + if (term != CONV_TERM_TAIL_BITING) > + dec->trellis->sums[0] = INT8_MAX * dec->n * dec->k; > +} > + > +static void _traceback(struct vdecoder *dec, > + unsigned state, uint8_t *out, int len) > +{ > + int i; > + unsigned path; > + > + for (i = len - 1; i >= 0; i--) { > + path = dec->paths[i][state] + 1; > + out[i] = dec->trellis->vals[state]; > + state = vstate_lshift(state, dec->k, path); > + } > +} > + > +static void _traceback_rec(struct vdecoder *dec, > + unsigned state, uint8_t *out, int len) > +{ > + int i; > + unsigned path; > + > + for (i = len - 1; i >= 0; i--) { > + path = dec->paths[i][state] + 1; > + out[i] = path ^ dec->trellis->vals[state]; > + state = vstate_lshift(state, dec->k, path); > + } > +} > + > +/* Traceback and generate decoded output > + * Find the largest accumulated path metric at the final state except for > + * the zero terminated case, where we assume the final state is always zero. > + */ > +static int traceback(struct vdecoder *dec, uint8_t *out, int term, int len) > +{ > + int i, sum, max = -1; > + unsigned path, state = 0; > + > + if (term != CONV_TERM_FLUSH) { > + for (i = 0; i < dec->trellis->num_states; i++) { > + sum = dec->trellis->sums[i]; > + if (sum > max) { > + max = sum; > + state = i; > + } > + } > + > + if (max < 0) > + return -EPROTO; > + } > + > + for (i = dec->len - 1; i >= len; i--) { > + path = dec->paths[i][state] + 1; > + state = vstate_lshift(state, dec->k, path); > + } > + > + if (dec->recursive) > + _traceback_rec(dec, state, out, len); > + else > + _traceback(dec, state, out, len); > + > + return 0; > +} > + > +/* Release decoder object */ > +static void free_vdec(struct vdecoder *dec) > +{ > + if (!dec) > + return; > + > + free(dec->paths[0]); > + free(dec->paths); > + free_trellis(dec->trellis); > + free(dec); > +} > + > +/* Allocate decoder object > + * Subtract the constraint length K on the normalization interval to > + * accommodate the initialization path metric at state zero. > + */ > +static struct vdecoder *alloc_vdec(const struct osmo_conv_code *code) > +{ > + int i, ns; > + struct vdecoder *dec; > + > + ns = NUM_STATES(code->K); > + > + dec = (struct vdecoder *) calloc(1, sizeof(struct vdecoder)); > + dec->n = code->N; > + dec->k = code->K; > + dec->recursive = conv_code_recursive(code); > + dec->intrvl = INT16_MAX / (dec->n * INT8_MAX) - dec->k; > + > + if (dec->k == 5) { > + switch (dec->n) { > + case 2: > + dec->metric_func = gen_metrics_k5_n2; > + break; > + case 3: > + dec->metric_func = gen_metrics_k5_n3; > + break; > + case 4: > + dec->metric_func = gen_metrics_k5_n4; > + break; > + default: > + goto fail; > + } > + } else if (dec->k == 7) { > + switch (dec->n) { > + case 2: > + dec->metric_func = gen_metrics_k7_n2; > + break; > + case 3: > + dec->metric_func = gen_metrics_k7_n3; > + break; > + case 4: > + dec->metric_func = gen_metrics_k7_n4; > + break; > + default: > + goto fail; > + } > + } else { > + goto fail; > + } > + > + if (code->term == CONV_TERM_FLUSH) > + dec->len = code->len + code->K - 1; > + else > + dec->len = code->len; > + > + dec->trellis = generate_trellis(code); > + if (!dec->trellis) > + goto fail; > + > + dec->paths = (int16_t **) malloc(sizeof(int16_t *) * dec->len); > + dec->paths[0] = vdec_malloc(ns * dec->len); > + for (i = 1; i < dec->len; i++) > + dec->paths[i] = &dec->paths[0][i * ns]; > + > + return dec; > +fail: > + free_vdec(dec); > + return NULL; > +} > + > +/* Depuncture sequence with nagative value terminated puncturing matrix */ > +static int depuncture(const int8_t *in, const int *punc, int8_t *out, int len) > +{ > + int i, n = 0, m = 0; > + > + for (i = 0; i < len; i++) { > + if (i == punc[n]) { > + out[i] = 0; > + n++; > + continue; > + } > + > + out[i] = in[m++]; > + } > + > + return 0; > +} > + > +/* Forward trellis recursion > + * Generate branch metrics and path metrics with a combined function. Only > + * accumulated path metric sums and path selections are stored. Normalize on > + * the interval specified by the decoder. > + */ > +static void _conv_decode(struct vdecoder *dec, const int8_t *seq, int _cnt) > +{ > + int i, len = dec->len; > + struct vtrellis *trellis = dec->trellis; > + > + for (i = 0; i < len; i++) { > + dec->metric_func(&seq[dec->n * i], > + trellis->outputs, > + trellis->sums, > + dec->paths[i], > + !(i % dec->intrvl)); > + } > +} > + > +/* Convolutional decode with a decoder object > + * Initial puncturing run if necessary followed by the forward recursion. > + * For tail-biting perform a second pass before running the backward > + * traceback operation. > + */ > +static int conv_decode(struct vdecoder *dec, const int8_t *seq, > + const int *punc, uint8_t *out, int len, int term) > +{ > + int cnt = 0; > + int8_t depunc[dec->len * dec->n]; > + > + reset_decoder(dec, term); > + > + if (punc) { > + depuncture(seq, punc, depunc, dec->len * dec->n); > + seq = depunc; > + } > + > + /* Propagate through the trellis with interval normalization */ > + _conv_decode(dec, seq, cnt); > + > + if (term == CONV_TERM_TAIL_BITING) > + _conv_decode(dec, seq, cnt); > + > + return traceback(dec, out, term, len); > +} > + > +/* All-in-one viterbi decoding */ > +int osmo_conv_decode_acc(const struct osmo_conv_code *code, > + const sbit_t *input, ubit_t *output) > +{ > + int rc; > + struct vdecoder *vdec; > + > + if ((code->N < 2) || (code->N > 4) || (code->len < 1) || > + ((code->K != 5) && (code->K != 7))) > + return -EINVAL; > + > + vdec = alloc_vdec(code); > + if (!vdec) > + return -EFAULT; > + > + rc = conv_decode(vdec, input, code->puncture, > + output, code->len, code->term); > + > + free_vdec(vdec); > + > + return rc; > +} > diff --git a/src/viterbi_gen.c b/src/viterbi_gen.c > new file mode 100644 > index 0000000..894d5ae > --- /dev/null > +++ b/src/viterbi_gen.c > @@ -0,0 +1,182 @@ > +/* > + * Viterbi decoder > + * Copyright (C) 2013, 2014 Thomas Tsou > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA > + */ > + > +#include > +#include > + > +/* Add-Compare-Select (ACS-Butterfly) > + * Compute 4 accumulated path metrics and 4 path selections. Note that path > + * selections are store as -1 and 0 rather than 0 and 1. This is to match > + * the output format of the SSE packed compare instruction 'pmaxuw'. > + */ > +void acs_butterfly(int state, int num_states, > + int16_t metric, int16_t *sum, > + int16_t *new_sum, int16_t *path) > +{ > + int state0, state1; > + int sum0, sum1, sum2, sum3; > + > + state0 = *(sum + (2 * state + 0)); > + state1 = *(sum + (2 * state + 1)); > + > + sum0 = state0 + metric; > + sum1 = state1 - metric; > + sum2 = state0 - metric; > + sum3 = state1 + metric; > + > + if (sum0 > sum1) { > + *new_sum = sum0; > + *path = -1; > + } else { > + *new_sum = sum1; > + *path = 0; > + } > + > + if (sum2 > sum3) { > + *(new_sum + num_states / 2) = sum2; > + *(path + num_states / 2) = -1; > + } else { > + *(new_sum + num_states / 2) = sum3; > + *(path + num_states / 2) = 0; > + } > +} > + > +/* Branch metrics unit N=2 */ > +void _gen_branch_metrics_n2(int num_states, const int8_t *seq, > + const int16_t *out, int16_t *metrics) > +{ > + int i; > + > + for (i = 0; i < num_states / 2; i++) { > + metrics[i] = seq[0] * out[2 * i + 0] + > + seq[1] * out[2 * i + 1]; > + } > +} > + > +/* Branch metrics unit N=3 */ > +void _gen_branch_metrics_n3(int num_states, const int8_t *seq, > + const int16_t *out, int16_t *metrics) > +{ > + int i; > + > + for (i = 0; i < num_states / 2; i++) > + metrics[i] = seq[0] * out[4 * i + 0] + > + seq[1] * out[4 * i + 1] + > + seq[2] * out[4 * i + 2]; > +} > + > +/* Branch metrics unit N=4 */ > +void _gen_branch_metrics_n4(int num_states, const int8_t *seq, > + const int16_t *out, int16_t *metrics) > +{ > + int i; > + > + for (i = 0; i < num_states / 2; i++) > + metrics[i] = seq[0] * out[4 * i + 0] + > + seq[1] * out[4 * i + 1] + > + seq[2] * out[4 * i + 2] + > + seq[3] * out[4 * i + 3]; > +} > + > +/* Path metric unit */ > +void _gen_path_metrics(int num_states, int16_t *sums, > + int16_t *metrics, int16_t *paths, int norm) > +{ > + int i; > + int16_t min; > + int16_t new_sums[num_states]; > + > + for (i = 0; i < num_states / 2; i++) { > + acs_butterfly(i, num_states, metrics[i], > + sums, &new_sums[i], &paths[i]); > + } > + > + if (norm) { > + min = new_sums[0]; > + for (i = 1; i < num_states; i++) { > + if (new_sums[i] < min) > + min = new_sums[i]; > + } > + > + for (i = 0; i < num_states; i++) > + new_sums[i] -= min; > + } > + > + memcpy(sums, new_sums, num_states * sizeof(int16_t)); > +} > + > +/* 16-state branch-path metrics units (K=5) */ > +void gen_metrics_k5_n2(const int8_t *seq, const int16_t *out, > + int16_t *sums, int16_t *paths, int norm) > +{ > + int16_t metrics[8]; > + > + _gen_branch_metrics_n2(16, seq, out, metrics); > + _gen_path_metrics(16, sums, metrics, paths, norm); > +} > + > +void gen_metrics_k5_n3(const int8_t *seq, const int16_t *out, > + int16_t *sums, int16_t *paths, int norm) > +{ > + int16_t metrics[8]; > + > + _gen_branch_metrics_n3(16, seq, out, metrics); > + _gen_path_metrics(16, sums, metrics, paths, norm); > + > +} > + > +void gen_metrics_k5_n4(const int8_t *seq, const int16_t *out, > + int16_t *sums, int16_t *paths, int norm) > +{ > + int16_t metrics[8]; > + > + _gen_branch_metrics_n4(16, seq, out, metrics); > + _gen_path_metrics(16, sums, metrics, paths, norm); > + > +} > + > +/* 64-state branch-path metrics units (K=7) */ > +void gen_metrics_k7_n2(const int8_t *seq, const int16_t *out, > + int16_t *sums, int16_t *paths, int norm) > +{ > + int16_t metrics[32]; > + > + _gen_branch_metrics_n2(64, seq, out, metrics); > + _gen_path_metrics(64, sums, metrics, paths, norm); > + > +} > + > +void gen_metrics_k7_n3(const int8_t *seq, const int16_t *out, > + int16_t *sums, int16_t *paths, int norm) > +{ > + int16_t metrics[32]; > + > + _gen_branch_metrics_n3(64, seq, out, metrics); > + _gen_path_metrics(64, sums, metrics, paths, norm); > + > +} > + > +void gen_metrics_k7_n4(const int8_t *seq, const int16_t *out, > + int16_t *sums, int16_t *paths, int norm) > +{ > + int16_t metrics[32]; > + > + _gen_branch_metrics_n4(64, seq, out, metrics); > + _gen_path_metrics(64, sums, metrics, paths, norm); > +} > -- > 1.9.0 > From tom at tsou.cc Thu May 8 18:15:40 2014 From: tom at tsou.cc (Tom Tsou) Date: Thu, 8 May 2014 14:15:40 -0400 Subject: [PATCH 1/4] core/conv: Add optimized Viterbi decoding In-Reply-To: References: <20140429041209.GA5135@phenom.hsd1.va.comcast.net> Message-ID: On Wed, May 7, 2014 at 12:25 PM, Sylvain Munaut <246tnt at gmail.com> wrote: > Some quick things I saw from a quick glance though: > - Some things that should be 'static' are not and they pollute the > global namespace Indeed. Internal calls in viterbi_gen.c should be static with leading underscores stripped since that seems to be the preferred style. If you were referring to others, please let me know. > - Anything that is in the global namespace needs the osmo_ (or even > osmo_conv_ here) prefix Ok. I purposely kept the internal struct definitions out of the public interface, but prefixing and exposing is fine. > - Did you check (and test in make test) that it works for all codes > that matches > "if ((code->N <= 4) && ((code->K == 5) || (code->K == 7)))" ? Almost all codes used by osmo-bts and a few others are covered by make check. Rates N=5 are skipped and TCH/HR passes with the posted puncturing fix for osmo-bts. There is an additional set of out-of-tree tests for Guassian noise, benchmarks, and some other things that probably don't apply to libosmocore. https://github.com/ttsou/osmo-conv-test > Also, to avoid exporting those internal symbols, I'm wondering if > #including the viterbi_gen.c from viterbi.c instead of compiling > separately wouldn't be better. But that's just a random idea ... I see three approaches: 1. Single file for generic and architecture specific implementations with large ifdef blocks. 2. Separate files with exported symbols (current patch). 3. Separate files with restricted visibility with __attribute__((__visibility__("hidden"))) or other combinations with the gcc -fvisibility flag. >> A beneficial change would be to modify the API to allow persistent >> decoder objects instead of performing an allocation and tear-down on >> every decoding call. From a performance standpoint, the current >> implementation is unnecessarily restricted by memory access and page >> faults for that reason. > > You can't change the existing API without breaking existing stuff, but you can > add a new all-in-one function that allows to give a persistent decoder object. I was just noting performance observations. For example, the SSE K=5 case on my machine is memory bound and not limited by compute resources. Given the effort to squeeze the current version behind the existing API, I won't be making breaking changes anytime soon. -TT From 246tnt at gmail.com Fri May 9 08:22:43 2014 From: 246tnt at gmail.com (Sylvain Munaut) Date: Fri, 9 May 2014 10:22:43 +0200 Subject: [PATCH 1/4] core/conv: Add optimized Viterbi decoding In-Reply-To: References: <20140429041209.GA5135@phenom.hsd1.va.comcast.net> Message-ID: Hi Tom, >> - Some things that should be 'static' are not and they pollute the >> global namespace > > Indeed. Internal calls in viterbi_gen.c should be static with leading > underscores stripped since that seems to be the preferred style. If > you were referring to others, please let me know. I don't mind the leading underscore honestly, especially in static, but if Holger prefers it that way, it's fine with me too. When I do a full review of the patch, I will look in more details into each call. >> - Anything that is in the global namespace needs the osmo_ (or even >> osmo_conv_ here) prefix > > Ok. I purposely kept the internal struct definitions out of the public > interface, but prefixing and exposing is fine. Not what I meant. 'structs' don't end up in the global namespace as long as they're not used in global function signatures, so you can keep them as is. I was thinking about functions. Among all those not marked 'static' and don't have an osmo_ prefix, I didn't yet do an exhaustive check to see what was an oversight and what's really needed to be global. >> - Did you check (and test in make test) that it works for all codes >> that matches >> "if ((code->N <= 4) && ((code->K == 5) || (code->K == 7)))" ? > > Almost all codes used by osmo-bts and a few others are covered by make > check. Rates N=5 are skipped and TCH/HR passes with the posted > puncturing fix for osmo-bts. I was more thinking about random codes. Like if someone invents a random code with N=4 and K=5, will it work ? When implementing it, you didnt see any other limitations that those right ? >> Also, to avoid exporting those internal symbols, I'm wondering if >> #including the viterbi_gen.c from viterbi.c instead of compiling >> separately wouldn't be better. But that's just a random idea ... > > I see three approaches: > > 1. Single file for generic and architecture specific implementations > with large ifdef blocks. > 2. Separate files with exported symbols (current patch). > 3. Separate files with restricted visibility with > __attribute__((__visibility__("hidden"))) or other combinations with > the gcc -fvisibility flag. I think we'll need to play with 3. Still probably need a prefix (not the full "osmo_conv_", but something less conflicty thatn gen_) > I was just noting performance observations. For example, the SSE K=5 > case on my machine is memory bound and not limited by compute > resources. Given the effort to squeeze the current version behind the > existing API, I won't be making breaking changes anytime soon. When I designed the API, I did do benchmark and just repeated them, and there is virtually no difference between the two versions. ( < 1% ) But I guess that's because in the current version, the 'decoder' struct stores virtually nothing that can be re-used between different bursts. (and malloc itself is pretty fast nowadays) In your case there is the treillis derived from the 'code' struct. And I guess this is where the performance hits comes from. An option would be to have an internal 'cache' of codes that have been used in the past so those data would be re-used. Basic flow of a decoder_init would be: { decoder = calloc(sizeof(decoder)); treillis = get_from_cache(code) if (!treillis) treillis = put_in_cache(gen_treillis(code)); decoder->treillis = treillis; } Since the number of different codes used in a single software is not big, this should be fairly easy to implement. Cheers, Sylvain From tom at tsou.cc Fri May 9 18:23:03 2014 From: tom at tsou.cc (Tom Tsou) Date: Fri, 9 May 2014 14:23:03 -0400 Subject: [PATCH 1/4] core/conv: Add optimized Viterbi decoding In-Reply-To: References: <20140429041209.GA5135@phenom.hsd1.va.comcast.net> Message-ID: On Fri, May 9, 2014 at 4:22 AM, Sylvain Munaut <246tnt at gmail.com> wrote: > Among all those not marked 'static' and don't have an osmo_ prefix, I didn't > yet do an exhaustive check to see what was an oversight and what's really > needed to be global. Overall, I don't think there should be _any_ non-static or global variable as that was the original intent. Admittedly, there were some oversights in the architecture specific BMU/PMU calls. >>> - Did you check (and test in make test) that it works for all codes >>> that matches >>> "if ((code->N <= 4) && ((code->K == 5) || (code->K == 7)))" ? >> >> Almost all codes used by osmo-bts and a few others are covered by make >> check. Rates N=5 are skipped and TCH/HR passes with the posted >> puncturing fix for osmo-bts. > > I was more thinking about random codes. Like if someone invents a random > code with N=4 and K=5, will it work ? When implementing it, you didnt see > any other limitations that those right ? The original implementation used octal based generator polynomials, so all non-degenerate cases are handled. By degenerate case I mean something like a K=7 code with generator polynomial of 0104, which is really a shifted K=5 code. No practical implementation will handle those cases of bad codes because the symmetric/anti-symmetric ACS properties of the trellis vanish. Similarly for recursive codes, the register feedback is based on the generator polynomial with the allowance that the systematic bit can be on any output. The AFS codes require that, which was really annoying. >> 1. Single file for generic and architecture specific implementations >> with large ifdef blocks. >> 2. Separate files with exported symbols (current patch). >> 3. Separate files with restricted visibility with >> __attribute__((__visibility__("hidden"))) or other combinations with >> the gcc -fvisibility flag. > > I think we'll need to play with 3. Still probably need a prefix (not > the full "osmo_conv_", but something less conflicty thatn gen_) Agreed on internal prefixing. Currently, libosmocore checks for the availability of hidden symbol visibility, sets SYMBOL_VISIBILITY="-fvisibility=hidden", but ignores use the result. Without making library wide changes or using ifdef blocks, the only approach is to mark the osmo_conv_gen calls with hidden visibility > When I designed the API, I did do benchmark and just repeated them, and > there is virtually no difference between the two versions. ( < 1% ) The allocation effects are case specific and more significant as the compute load drops. Also, you may have noticed the bitswap operations, which only exist because the trellis and API have conflicting trellis endian formats. Those calls are only used during initialization. Parallel decoding threads also seems affected. Overall though, for GSM where the data rates are quite low, the allocate and tear-down effects, while measurable, are probably not significant enough to justify an API change. There may be a case on ARM or Epiphany, but I have not tested those platforms enough to comment. > But I guess that's because in the current version, the 'decoder' struct > stores virtually nothing that can be re-used between different bursts. > (and malloc itself is pretty fast nowadays) The main memory allocation is the path metric storage, which is unavoidable, and similar in both cases. The current version does store paths with 8-bits instead of 16-bits, so that allocation is halved. The SSE outputs are 16-bit so converting to 8-bit at every stage wasn't worth the overhead. Still, cache performance on the submitted code codes out far ahead. $ perf stat -e cache-misses,page-faults ./conv_test -c 3 -b -i 500000 -o ================================================= [+] Testing: GPRS CS3 [.] Specs: (N=2, K=5, non-recursive, flushed, not punctured) [.] Input length : ret = 334 exp = 334 -> OK [.] Output length : ret = 676 exp = 676 -> OK [.] Performance benchmark: [..] Encoding / Decoding 500000 bursts on 1 thread(s): [..] Testing base: [..] Elapsed time....................... 18.189684 secs [..] Rate............................... 9.181028 Mbps Performance counter stats for './conv_test -c 3 -b -i 500000 -o': 65,116 cache-misses 284 page-faults 18.191569647 seconds time elapsed $ perf stat -e cache-misses,page-faults ./conv_test -c 3 -b -i 500000 -s ================================================= [+] Testing: GPRS CS3 [.] Specs: (N=2, K=5, non-recursive, flushed, not punctured) [.] Input length : ret = 334 exp = 334 -> OK [.] Output length : ret = 676 exp = 676 -> OK [.] Performance benchmark: [..] Encoding / Decoding 500000 bursts on 1 thread(s): [..] Testing SIMD: [..] Elapsed time....................... 1.820236 secs [..] Rate............................... 91.746345 Mbps Performance counter stats for './conv_test -c 3 -b -i 500000 -s': 11,508 cache-misses 288 page-faults 1.822036339 seconds time elapsed > In your case there is the treillis derived from the 'code' struct. And I > guess this is where the performance hits comes from. An option would be > to have an internal 'cache' of codes that have been used in the past > so those data would be re-used. Internal caching was in the original implementation, but stripped from the submitted version mainly for simplicity and avoiding the need for global variables, though we seem to be having that discussion anyway ;-) The trellis values can be cached based on pointer or hashed code. That works well until threading is involved and cache access needs to be locked. Those are features I need, but can probably be ignored in this case. Again, I think the API should be kept intact. Internal caching, can be a topic for later discussion. -TT From tom at tsou.cc Thu May 1 18:02:03 2014 From: tom at tsou.cc (Tom Tsou) Date: Thu, 1 May 2014 14:02:03 -0400 Subject: [PATCH 0/4] core/conv: Fast Viterbi decoding In-Reply-To: References: <20140429041352.GA5213@phenom.hsd1.va.comcast.net> Message-ID: On Tue, Apr 29, 2014 at 2:09 AM, Alexander Chemeris wrote: > May I suggest you to check in the test cases into a test or contrib > directory of libosmocore? This will help ensure that we do not loose them > and that they stay in sync with the code. Ideally, we should also run > validity checks on "make check" as well. The patch for additional test codes was already posted and is run with 'make check'. Those cases mostly serve as regression tests. For AWGN tests, I feel less certain that wireless channel modeling belong in libosmocore. The error rate simulations will not fit the current make check model since they are probabilistic and non-deterministic by definition. -TT From koue at chaosophia.net Wed May 7 08:06:20 2014 From: koue at chaosophia.net (Nikola Kolev) Date: 07 May 2014 11:06:20 +0300 Subject: [PATCH] openbsc: Fix for FreeBSD In-Reply-To: <20140430154801.GO3501@xiaoyu.lan> References: <20140430154801.GO3501@xiaoyu.lan> Message-ID: On Apr 30 2014, Holger Hans Peter Freyther wrote: >On Wed, Apr 30, 2014 at 05:01:55PM +0300, Nikola Kolev wrote: >> Fix for FreeBSD. > >Hey! > >could you extend the commit message a bit? E.g. include the compile >error you fixed and mention how IF_RECVIF is compatible to the >bindtodevice. The support to IF_SENDIF doesn't seem to have ever >been finished in FreeBSD. > > > I separated the patch file to 2 different files because of different commit messages and sent them back to the mail list. -- Nikola From holger at freyther.de Wed May 7 12:00:48 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Wed, 7 May 2014 14:00:48 +0200 Subject: [PATCH] openbsc: Fix for FreeBSD In-Reply-To: References: <20140430154801.GO3501@xiaoyu.lan> Message-ID: <20140507120048.GD30167@xiaoyu.lan> On Wed, May 07, 2014 at 11:06:20AM +0300, Nikola Kolev wrote: Hi! > I separated the patch file to 2 different files because of different commit > messages and sent them back to the mail list. please use "git commit" and then git format-patch and send the result of it. Using git send-email gives you extra points. Like FreeBSD is an engineering project, I try to have Osmocom become one too. So the commit message should be held to the same standard as the rest of the code. E.g. if your code works with SO_RECVIF and the commit message talks about SO_SENDIF we need to fix either one or the other (and seeing that the SO_SENDIF code was never finished the commit message should be changed though). cheers holger From ottawa712 at gmail.com Fri May 2 13:25:15 2014 From: ottawa712 at gmail.com (ottawa ottawa) Date: Fri, 2 May 2014 09:25:15 -0400 Subject: PDP deactivation on a particular cell phone Message-ID: Hi Gurus I am using OpenBSC/GPRS with nanoBTS. Thanks everybody for the great work. GPRS works well with many cell phone, but for particular cell phone its not working. I saw Olaf Schulz posting (subject: GPRS problems with Nokia Handsets dated 4th May 2012). Saw his pcap file and mine is similar too. Frank Mass suggested a patch to overcome this problem in his posting (subject gprs_llc.c foreighn TLLI is stored but not searched, dated 30 April 2012). I have implemented that patch but still not working. Can any body suggest something. Please find the osmo-sgsn trace <0011> gprs_bssgp.c:376 BSSGP TLLI=0xabfafd41 Rx UPLINK-UNITDATA <0012> gprs_llc.c:551 LLC SAPI=1 C FCS=0x76d7d9CMD=UI DATA <0012> gprs_llc.c:95 TLLI 0xabfafd41 is foreign, converting to local TLLI 0xebfafd41 <0012> gprs_llc.c:245 LLC RX: unknown TLLI 0xabfafd41, creating LLME on the fly <0011> gprs_bssgp.c:753 BSSGP BVCI=2 Rx Flow Control BVC <0011> gprs_bssgp.c:376 BSSGP TLLI=0xabfafd41 Rx UPLINK-UNITDATA <0012> gprs_llc.c:551 LLC SAPI=1 R FCS=0x57768eCMD=XID DATA <0011> gprs_bssgp.c:376 BSSGP TLLI=0xabfafd41 Rx UPLINK-UNITDATA <0012> gprs_llc.c:551 LLC SAPI=1 C FCS=0x9ab10aCMD=UI DATA <0012> gprs_llc.c:598 TLLI=abfafd41 dropping UI, N(U=0) not in window V(URV(UR:3). <0011> gprs_bssgp.c:753 BSSGP BVCI=2 Rx Flow Control BVC <0011> gprs_bssgp.c:753 BSSGP BVCI=2 Rx Flow Control BVC <0011> gprs_bssgp.c:376 BSSGP TLLI=0x7d3b00c1 Rx UPLINK-UNITDATA <0012> gprs_llc.c:551 LLC SAPI=1 C FCS=0xfd5011CMD=UI DATA <0012> gprs_llc.c:245 LLC RX: unknown TLLI 0x7d3b00c1, creating LLME on the fly <0011> gprs_bssgp.c:753 BSSGP BVCI=2 Rx Flow Control BVC <0011> gprs_bssgp.c:376 BSSGP TLLI=0x7d3b00c1 Rx UPLINK-UNITDATA <0012> gprs_llc.c:551 LLC SAPI=1 C FCS=0x11fb2fCMD=UI DATA <0011> gprs_bssgp.c:376 BSSGP TLLI=0x7d3b00c1 Rx UPLINK-UNITDATA <0012> gprs_llc.c:551 LLC SAPI=1 C FCS=0xea1c55CMD=UI DATA <0011> gprs_bssgp.c:753 BSSGP BVCI=2 Rx Flow Control BVC <0011> gprs_bssgp.c:753 BSSGP BVCI=2 Rx Flow Control BVC <0011> gprs_bssgp.c:376 BSSGP TLLI=0xe23c0990 Rx UPLINK-UNITDATA <0012> gprs_llc.c:551 LLC SAPI=1 C FCS=0x2a6a81CMD=UI DATA <000f> sgsn_libgtp.c:126 Create PDP Context <000f> sgsn_libgtp.c:379 libgtp cb_conf(type=16, cause=128, pdp=0x7feafc152320, cbp=0x6bcf50) <000f> sgsn_libgtp.c:265 Received CREATE PDP CTX CONF, cause=128(Request accepted) <0013> gprs_sndcp.c:297 SNSM-ACTIVATE.ind (lle=0x6bbe60 TLLI=e23c0990, SAPI=3, NSAPI=5) <0011> gprs_bssgp.c:753 BSSGP BVCI=2 Rx Flow Control BVC <0011> gprs_bssgp.c:753 BSSGP BVCI=2 Rx Flow Control BVC <0011> gprs_bssgp.c:753 BSSGP BVCI=2 Rx Flow Control BVC <0011> gprs_bssgp.c:376 BSSGP TLLI=0xe23c0990 Rx UPLINK-UNITDATA <0012> gprs_llc.c:551 LLC SAPI=1 C FCS=0x819789CMD=UI DATA <000f> sgsn_libgtp.c:212 Delete PDP Context <000f> sgsn_libgtp.c:402 PDP Context was deleted <000f> sgsn_libgtp.c:379 libgtp cb_conf(type=20, cause=128, pdp=(nil), cbp=0x6bcf50) <000f> sgsn_libgtp.c:321 Received DELETE PDP CTX CONF, cause=128(Request accepted) <0013> gprs_sndcp.c:320 SNSM-DEACTIVATE.ind (lle=0x6bbe60, TLLI=e23c0990, SAPI=3, NSAPI=5) John -------------- next part -------------- An HTML attachment was scrubbed... URL: From ciaby at autistici.org Sun May 4 18:08:06 2014 From: ciaby at autistici.org (Ciaby) Date: Sun, 04 May 2014 20:08:06 +0200 Subject: Unintentional fuckup :( Message-ID: <53668206.4000209@autistici.org> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA512 Sorry everyone, I just pushed the wrong master branch to master on git :( Can someone with the latest version push back the correct one? /ME feels like an idiot... Sorry again. Ciaby -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/ iF4EAREKAAYFAlNmggEACgkQC30ZhxNccpE7HQD/ez0n7e3kqDFjX8nucLGimAxZ L5sBgJ3blpWYde9yKsQBAJVsWLjsxxO6WxghfrBHCm8/ndmlgm80sw+Es2TGd8t0 =ytos -----END PGP SIGNATURE----- From ciaby at autistici.org Sun May 4 18:24:18 2014 From: ciaby at autistici.org (Ciaby) Date: Sun, 04 May 2014 20:24:18 +0200 Subject: Unintentional fuckup :( In-Reply-To: <53668206.4000209@autistici.org> References: <53668206.4000209@autistici.org> Message-ID: <536685D2.8030708@autistici.org> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA512 On 05/04/2014 08:08 PM, Ciaby wrote: > Sorry everyone, I just pushed the wrong master branch to master on > git :( Can someone with the latest version push back the correct > one? /ME feels like an idiot... Sorry again. Ok, resetting to the latest correct one and pushing it doesn't seem to work... any better idea? Ciaby -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/ iF4EAREKAAYFAlNmhc0ACgkQC30ZhxNccpGH6gD+NLrMCKKKF4nT/ey4Qlo8a/Hx RjCpYpKTvl8Vyv2a+9MA/RFHaZeHfYmXayMwteqS3M1SjenXjMvFZkaErO3pQ50q =yNl7 -----END PGP SIGNATURE----- From ciaby at autistici.org Sun May 4 18:48:30 2014 From: ciaby at autistici.org (Ciaby) Date: Sun, 04 May 2014 20:48:30 +0200 Subject: Unintentional fuckup :( In-Reply-To: <536685D2.8030708@autistici.org> References: <53668206.4000209@autistici.org> <536685D2.8030708@autistici.org> Message-ID: <53668B7E.6090201@autistici.org> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA512 On 05/04/2014 08:24 PM, Ciaby wrote: > Ok, resetting to the latest correct one and pushing it doesn't seem > to work... any better idea? It did work at the end... git push -f :P Ok, sorry again for all the mess. I won't do it again. Promise. Cheers Ciaby -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/ iF4EAREKAAYFAlNmi3kACgkQC30ZhxNccpGR9AD/U8cmIoNKpnYX0mndEJlblImk zYNE079nO5DYclPrB5wBAJdzPkw264vMFEU5Y0M71YoarxiJkc8IArnCnfIPAZiu =VIe+ -----END PGP SIGNATURE----- From anayuso at sysmocom.de Mon May 5 14:04:02 2014 From: anayuso at sysmocom.de (Alvaro Neira Ayuso) Date: Mon, 5 May 2014 16:04:02 +0200 Subject: [libosmocore PATCH 1/4] protocol/gsm_12_21.h: Add the Manufacturer Attribute ID O_REDUCEPOWER. Message-ID: <1399298642-14103-1-git-send-email-anayuso@sysmocom.de> From: ?lvaro Neira Ayuso Signed-off-by: Alvaro Neira Ayuso --- include/osmocom/gsm/protocol/gsm_12_21.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/osmocom/gsm/protocol/gsm_12_21.h b/include/osmocom/gsm/protocol/gsm_12_21.h index 694df93..b1725d5 100644 --- a/include/osmocom/gsm/protocol/gsm_12_21.h +++ b/include/osmocom/gsm/protocol/gsm_12_21.h @@ -486,6 +486,8 @@ enum abis_nm_attr { NM_ATT_BS11_ANT_TYPE = 0xf4, NM_ATT_BS11_PLL_MODE = 0xfc, NM_ATT_BS11_PASSWORD = 0xfd, + + NM_ATT_O_REDUCEPOWER = 0x01, }; #define NM_ATT_BS11_FILE_DATA NM_ATT_EVENT_TYPE -- 1.7.10.4 From holger at freyther.de Thu May 15 19:55:53 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Thu, 15 May 2014 21:55:53 +0200 Subject: [libosmocore PATCH 1/4] protocol/gsm_12_21.h: Add the Manufacturer Attribute ID O_REDUCEPOWER. In-Reply-To: <1399298642-14103-1-git-send-email-anayuso@sysmocom.de> References: <1399298642-14103-1-git-send-email-anayuso@sysmocom.de> Message-ID: <20140515195553.GA21990@xiaoyu.lan> On Mon, May 05, 2014 at 04:04:02PM +0200, Alvaro Neira Ayuso wrote: > diff --git a/include/osmocom/gsm/protocol/gsm_12_21.h b/include/osmocom/gsm/protocol/gsm_12_21.h > index 694df93..b1725d5 100644 > --- a/include/osmocom/gsm/protocol/gsm_12_21.h > +++ b/include/osmocom/gsm/protocol/gsm_12_21.h > @@ -486,6 +486,8 @@ enum abis_nm_attr { > NM_ATT_BS11_ANT_TYPE = 0xf4, > NM_ATT_BS11_PLL_MODE = 0xfc, > NM_ATT_BS11_PASSWORD = 0xfd, > + > + NM_ATT_O_REDUCEPOWER = 0x01, okay, added it. The sorting was already inconsistent. Either group by source (spec, BS11, ipa, osmocom) or sort by value. No action from you is required though. From laforge at gnumonks.org Mon May 19 09:48:47 2014 From: laforge at gnumonks.org (Harald Welte) Date: Mon, 19 May 2014 11:48:47 +0200 Subject: [libosmocore PATCH 1/4] protocol/gsm_12_21.h: Add the Manufacturer Attribute ID O_REDUCEPOWER. In-Reply-To: <1399298642-14103-1-git-send-email-anayuso@sysmocom.de> References: <1399298642-14103-1-git-send-email-anayuso@sysmocom.de> Message-ID: <20140519094847.GV14533@nataraja> Hi Alvaro, I had to modifiy/update this patch by the attached patch, it contains a quite verbose message stating the rationale why. The corresponding code out of osmo-bts hd to be reverted, I will follow up with more explanations as to why. -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From laforge at gnumonks.org Mon May 19 09:25:46 2014 From: laforge at gnumonks.org (Harald Welte) Date: Mon, 19 May 2014 11:25:46 +0200 Subject: [PATCH] Fix introducing osmocom speficic OML attributes Message-ID: Rename NM_ATT_O_REDUCEPOWER to NM_ATT_OSMO_REDUCEPOWER, which makes it more clear that this is an osmcoom specific attribute. Also, we cannot simply overload 0x01 as an already defined OML attribute. The problem is quite simple: When we use abis_nm_att_tlvdef during the TLV parse, 0x01 will match to NM_ATT_ABIS_CHANNEL, which is defined as { TLV_TYPE_FIXED, 3 }. So instead, we need to introduce a new abis_nm_osmo_att_tlvdef[], which has to be patched into abis_nm_att_tlvdef[] by the means of tlv_def_patch(), exactly how we do it for bs-11 and nanobts specific attributes. I'm using 0xfe for the attribute, as 0xfe doesn't overlap with the IPA specific attribues (and we might want to combine/merge the 12.21 plus IPA plus osmocom spefici attributes) --- include/osmocom/gsm/protocol/gsm_12_21.h | 4 +++- src/gsm/abis_nm.c | 7 +++++++ src/gsm/libosmogsm.map | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/include/osmocom/gsm/protocol/gsm_12_21.h b/include/osmocom/gsm/protocol/gsm_12_21.h index b1725d5..ad0890c 100644 --- a/include/osmocom/gsm/protocol/gsm_12_21.h +++ b/include/osmocom/gsm/protocol/gsm_12_21.h @@ -487,7 +487,9 @@ enum abis_nm_attr { NM_ATT_BS11_PLL_MODE = 0xfc, NM_ATT_BS11_PASSWORD = 0xfd, - NM_ATT_O_REDUCEPOWER = 0x01, + /* osmocom (osmo-bts) specific attributes, used in combination + * with the "org.osmocom" manufacturer identification */ + NM_ATT_OSMO_REDUCEPOWER = 0xfe, /* TLV_TYPE_TV */ }; #define NM_ATT_BS11_FILE_DATA NM_ATT_EVENT_TYPE diff --git a/src/gsm/abis_nm.c b/src/gsm/abis_nm.c index 2c23a64..7a1f664 100644 --- a/src/gsm/abis_nm.c +++ b/src/gsm/abis_nm.c @@ -323,6 +323,13 @@ const struct tlv_definition abis_nm_att_tlvdef = { }, }; +/*! \brief org.osmocom GSM A-bis OML TLV parser definition */ +const struct tlv_definition abis_nm_osmo_att_tlvdef = { + .def = { + [NM_ATT_OSMO_REDUCEPOWER] = { TLV_TYPE_TV }, + }, +}; + /*! \brief Human-readable strings for A-bis OML Object Class */ const struct value_string abis_nm_obj_class_names[] = { { NM_OC_SITE_MANAGER, "SITE-MANAGER" }, diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map index 3c5025d..cab4fc4 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -10,6 +10,7 @@ abis_nm_event_type_name; abis_nm_nack_cause_name; abis_nm_nack_name; abis_nm_att_tlvdef; +abis_nm_osmo_att_tlvdef; abis_nm_obj_class_names; abis_nm_opstate_name; abis_nm_nacks; -- 2.0.0.rc2 --9Ek0hoCL9XbhcSqy-- From holger at freyther.de Mon May 19 11:49:27 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Mon, 19 May 2014 13:49:27 +0200 Subject: [libosmocore PATCH 1/4] protocol/gsm_12_21.h: Add the Manufacturer Attribute ID O_REDUCEPOWER. In-Reply-To: <20140519094847.GV14533@nataraja> References: <1399298642-14103-1-git-send-email-anayuso@sysmocom.de> <20140519094847.GV14533@nataraja> Message-ID: <20140519114927.GK25451@xiaoyu.lan> On Mon, May 19, 2014 at 11:48:47AM +0200, Harald Welte wrote: > Rename NM_ATT_O_REDUCEPOWER to NM_ATT_OSMO_REDUCEPOWER, which > makes it more clear that this is an osmcoom specific attribute. > > Also, we cannot simply overload 0x01 as an already defined OML > attribute. The problem is quite simple: When we use abis_nm_att_tlvdef > during the TLV parse, 0x01 will match to NM_ATT_ABIS_CHANNEL, > which is defined as { TLV_TYPE_FIXED, 3 }. But we already do have overlap. At least between BS11 and ipaccess. How is it different from GSM to osmocom? We could argue that the vendor values should not be in the gsm enum but sit somewhere else? Can you please elaborate? > I'm using 0xfe for the attribute, as 0xfe doesn't overlap with the IPA > specific attribues (and we might want to combine/merge the 12.21 plus > IPA plus osmocom spefici attributes) typo(s). :) From laforge at gnumonks.org Mon May 19 13:44:00 2014 From: laforge at gnumonks.org (Harald Welte) Date: Mon, 19 May 2014 15:44:00 +0200 Subject: [libosmocore PATCH 1/4] protocol/gsm_12_21.h: Add the Manufacturer Attribute ID O_REDUCEPOWER. In-Reply-To: <20140519114927.GK25451@xiaoyu.lan> References: <1399298642-14103-1-git-send-email-anayuso@sysmocom.de> <20140519094847.GV14533@nataraja> <20140519114927.GK25451@xiaoyu.lan> Message-ID: <20140519134400.GC14533@nataraja> Hi Holger, On Mon, May 19, 2014 at 01:49:27PM +0200, Holger Hans Peter Freyther wrote: > On Mon, May 19, 2014 at 11:48:47AM +0200, Harald Welte wrote: > > > Rename NM_ATT_O_REDUCEPOWER to NM_ATT_OSMO_REDUCEPOWER, which > > makes it more clear that this is an osmcoom specific attribute. > > > > Also, we cannot simply overload 0x01 as an already defined OML > > attribute. The problem is quite simple: When we use abis_nm_att_tlvdef > > during the TLV parse, 0x01 will match to NM_ATT_ABIS_CHANNEL, > > which is defined as { TLV_TYPE_FIXED, 3 }. > > But we already do have overlap. At least between BS11 and ipaccess. > How is it different from GSM to osmocom? Yes, this is not an issue as e.g. openbsc uses the tlv_def_patch() function to merge the generic 12.21 ones with either the BS11 ones, or the ip.access ones. There is no overlapping in those respective sets. You can of couse not merge all three of them. During the patching, the vendor-specific IEI can override a 12.21 IEI / TLV definition. I think Siemens has in some cases used TV where the spec says TV16 or vice versa. But even if it was the intention of the osmocom IEI to override the NM_ATT_ABIS_CHANNEL, then the code would first have to create a patched tlv definition table, and then use tlv_parse with that patched table, rather than the pristine 12.21 one. > We could argue that the vendor values should not be in the gsm enum > but sit somewhere else? That might be an option, but its a mere difference in style. If they're all in one large enum, one can at least see their values/ranges in one spot. > > I'm using 0xfe for the attribute, as 0xfe doesn't overlap with the IPA > > specific attribues (and we might want to combine/merge the 12.21 plus > > IPA plus osmocom spefici attributes) > > typo(s). :) my apologies. well, as long as people can unserstand what I read, I don't really think it is the most useful way to use my time to re-read everything in order to spot + fix them. -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From holger at freyther.de Mon May 19 14:03:51 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Mon, 19 May 2014 16:03:51 +0200 Subject: [libosmocore PATCH 1/4] protocol/gsm_12_21.h: Add the Manufacturer Attribute ID O_REDUCEPOWER. In-Reply-To: <20140519134400.GC14533@nataraja> References: <1399298642-14103-1-git-send-email-anayuso@sysmocom.de> <20140519094847.GV14533@nataraja> <20140519114927.GK25451@xiaoyu.lan> <20140519134400.GC14533@nataraja> Message-ID: <20140519140351.GC29651@xiaoyu.lan> On Mon, May 19, 2014 at 03:44:00PM +0200, Harald Welte wrote: > Yes, this is not an issue as e.g. openbsc uses the tlv_def_patch() > function to merge the generic 12.21 ones with either the BS11 ones, or > the ip.access ones. There is no overlapping in those respective sets. > You can of couse not merge all three of them. During the patching, the > vendor-specific IEI can override a 12.21 IEI / TLV definition. I think > Siemens has in some cases used TV where the spec says TV16 or vice > versa. > > But even if it was the intention of the osmocom IEI to override the > NM_ATT_ABIS_CHANNEL, then the code would first have to create a patched > tlv definition table, and then use tlv_parse with that patched table, > rather than the pristine 12.21 one. My intention of starting with using 0x1 was for the usage in vendor defined messages. I didn't intend to use these values to add IEs to existing GSM 12.21 messages. So maybe this is an argument to move the enum somewhere else. I didn't think of the tlv_ table for this enum and didn't notice it in the review. From my point of view I would favor to move this value into a new enum and introduce a new TLV table for these manufacturer messages? From mihal.grznar at gmail.com Mon May 5 21:13:37 2014 From: mihal.grznar at gmail.com (=?UTF-8?Q?Michal_Grzn=C3=A1r?=) Date: Mon, 5 May 2014 23:13:37 +0200 Subject: OsmoSGSN [PATCH], Network Service Message-ID: Hi, I am using OsmoSGSN in topology with OpenGGSN and proprietary simulator of BSS. There was a problem with an implementation of Network service, cause Network Service implementation in the simulator of BSS is based on different release of 3GPP standard (3GPP TS 48. 016 v7. 4. 0 (2008-04)/Network service (Release 7))...and the problem is that in IP-subnetwork, which I am using there is no use for RESET or UNBLOCK procedure, so I had to do a PATCH in gprs_ns.c, which was needed to complete succesful connection between sim-bss and OsmoSGSN: switch (nsh->pdu_type) { case NS_PDUT_ALIVE: +++ LOGP(DNS, LOGL_INFO, "Rx NS ALIVE\n"); +++ /*mark NS-VC as alive*/ +++ (*nsvc)->state = NSE_S_ALIVE; +++ (*nsvc)->remote_state = NSE_S_ALIVE; +++ /*initiate TEST procedure: Send ALIVE_ACK and start timer*/ +++ rc = gprs_ns_tx_simple((*nsvc), NS_PDUT_ALIVE_ACK); +++ nsvc_start_timer((*nsvc), NSVC_TIMER_TNS_TEST); +++ break; . . . } another PATCH I needed to do was to change a little bit procedure for allocation of P-TMSI in procedure uint32_t sgsn_alloc_ptmsi(void) in gprs_sgsn.c uint32_t sgsn_alloc_ptmsi(void) { struct sgsn_mm_ctx *mm; uint32_t ptmsi; restart: +++ ptmsi = rand() | 0xc0000000; /*because of GPRS IMSI ATTACH*/ llist_for_each_entry(mm, &sgsn_mm_ctxts, list) { if (mm->p_tmsi == ptmsi) goto restart; } return ptmsi; } because in GPRS IMSI ATTACH in message ATTACH COMPLETE (3GPP 24.008, 23.003, 48.018) there is new TLLI==new allocated P-TMSI and I need local TLLI, so I had to do it this way regards Michal -------------- next part -------------- An HTML attachment was scrubbed... URL: From laforge at gnumonks.org Sat May 17 11:50:33 2014 From: laforge at gnumonks.org (Harald Welte) Date: Sat, 17 May 2014 13:50:33 +0200 Subject: OsmoSGSN [PATCH], Network Service In-Reply-To: References: Message-ID: <20140517115033.GC14533@nataraja> Hi Michal, thanks a lot for reporting back on your experience. Hoewever, it is customary to post changes as unified diff ('diff -u' format here on this list for review. I have a hard time understanding the format that you posted. Can you pleaes re-post your changes? Either with diff -u created manually, or with 'git diff' or similar. On Mon, May 05, 2014 at 11:13:37PM +0200, Michal Grzn?r wrote: > Hi, I am using OsmoSGSN in topology with OpenGGSN and proprietary simulator > and the problem is that in IP-subnetwork, which I am using there is no > use for RESET or UNBLOCK procedure, so I had to do a PATCH in > gprs_ns.c, which was needed to complete succesful connection between > sim-bss and OsmoSGSN: If you would like to see such code merged, please extend osmo-sgsn so that the type of BSS can be configured via vty, and make the code conditional. At that point you could simply have a different config file for your sim-bss than we have. > another PATCH I needed to do was to change a little bit procedure for > allocation of P-TMSI in procedure uint32_t sgsn_alloc_ptmsi(void) in > gprs_sgsn.c > > uint32_t sgsn_alloc_ptmsi(void) > { > struct sgsn_mm_ctx *mm; > uint32_t ptmsi; > > restart: > +++ ptmsi = rand() | 0xc0000000; /*because of GPRS IMSI > ATTACH*/ > llist_for_each_entry(mm, &sgsn_mm_ctxts, list) { > if (mm->p_tmsi == ptmsi) > goto restart; > } > return ptmsi; > } > > because in GPRS IMSI ATTACH in message ATTACH COMPLETE (3GPP 24.008, > 23.003, 48.018) there is new TLLI==new allocated P-TMSI and I need local > TLLI, so I had to do it this way This is most certainly not the right way to fix the problem. The TLLI is generated at a different layer than the P-TMSI. The P-TMSI should be completely random, and the TLLI derived from that should mask the upper bits, using the gprs_tmsi2tlli() function. Can you please explain more what the actual problem was and how it manifested iself? If possible, include pcap traces for further illustration. Thanks, Harald -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From mihal.grznar at gmail.com Fri May 23 09:44:40 2014 From: mihal.grznar at gmail.com (=?UTF-8?Q?Michal_Grzn=C3=A1r?=) Date: Fri, 23 May 2014 11:44:40 +0200 Subject: OsmoSGSN [PATCH], Network Service In-Reply-To: <20140517115033.GC14533@nataraja> References: <20140517115033.GC14533@nataraja> Message-ID: Hi, I am sorry for my previous bad post format. There are the right diff files. And the problem was as I said in Imsi attach procedure new TLLI == new allocated P-tmsi, and there was a problem that the function gprs_tmsi2tlli() function there was not called and so I had to mask the upper bits in function where the p-tmsi is allocated, there is also a pcap trace where you can see it. thanks, regards Michal 2014-05-17 13:50 GMT+02:00 Harald Welte : > Hi Michal, > > thanks a lot for reporting back on your experience. > > Hoewever, it is customary to post changes as unified diff ('diff -u' > format here on this list for review. I have a hard time understanding > the format that you posted. Can you pleaes re-post your changes? > Either with diff -u created manually, or with 'git diff' or similar. > > On Mon, May 05, 2014 at 11:13:37PM +0200, Michal Grzn?r wrote: > > Hi, I am using OsmoSGSN in topology with OpenGGSN and proprietary > simulator > > and the problem is that in IP-subnetwork, which I am using there is no > > use for RESET or UNBLOCK procedure, so I had to do a PATCH in > > gprs_ns.c, which was needed to complete succesful connection between > > sim-bss and OsmoSGSN: > > If you would like to see such code merged, please extend osmo-sgsn so > that the type of BSS can be configured via vty, and make the code > conditional. At that point you could simply have a different config > file for your sim-bss than we have. > > > another PATCH I needed to do was to change a little bit procedure for > > allocation of P-TMSI in procedure uint32_t sgsn_alloc_ptmsi(void) in > > gprs_sgsn.c > > > > uint32_t sgsn_alloc_ptmsi(void) > > { > > struct sgsn_mm_ctx *mm; > > uint32_t ptmsi; > > > > restart: > > +++ ptmsi = rand() | 0xc0000000; /*because of GPRS IMSI > > ATTACH*/ > > llist_for_each_entry(mm, &sgsn_mm_ctxts, list) { > > if (mm->p_tmsi == ptmsi) > > goto restart; > > } > > return ptmsi; > > } > > > > because in GPRS IMSI ATTACH in message ATTACH COMPLETE (3GPP 24.008, > > 23.003, 48.018) there is new TLLI==new allocated P-TMSI and I need local > > TLLI, so I had to do it this way > > This is most certainly not the right way to fix the problem. The TLLI > is generated at a different layer than the P-TMSI. The P-TMSI should be > completely random, and the TLLI derived from that should mask the upper > bits, using the gprs_tmsi2tlli() function. > > Can you please explain more what the actual problem was and how it > manifested iself? If possible, include pcap traces for further > illustration. > > Thanks, > Harald > > -- > - Harald Welte > http://laforge.gnumonks.org/ > > ============================================================================ > "Privacy in residential applications is a desirable marketing option." > (ETSI EN 300 175-7 Ch. > A6) > -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- --- gprs_ns_before_patch.c 2014-05-23 10:36:09.041829000 +0200 +++ gprs_ns_patch.c 2014-05-23 10:34:17.101829001 +0200 @@ -1217,16 +1217,14 @@ switch (nsh->pdu_type) { case NS_PDUT_ALIVE: - /* If we're dead and blocked and suddenly receive a - * NS-ALIVE out of the blue, we might have been re-started - * and should send a NS-RESET to make sure everything recovers - * fine. */ - -LOGP(DNS, LOGL_INFO, "Rx NS ALIVE\n"); -if ((*nsvc)->state == NSE_S_BLOCKED) - rc = gprs_ns_tx_reset((*nsvc), NS_CAUSE_PDU_INCOMP_PSTATE); - else - rc = gprs_ns_tx_alive_ack(*nsvc); + LOGP(DNS, LOGL_INFO, "Rx NS ALIVE\n"); + rc = gprs_ns_tx_alive_ack(*nsvc); + /*mark NS-VC as unblocked and active*/ + (*nsvc)->state = NSE_S_ALIVE; + (*nsvc)->remote_state = NSE_S_ALIVE; + /*Initiate TEST proc.: Send ALIVE_ACK and start timer*/ + rc = gprs_ns_tx_simple((*nsvc), NS_PDUT_ALIVE_ACK); + nsvc_start_timer((*nsvc), NSVC_TIMER_TNS_TEST); break; case NS_PDUT_ALIVE_ACK: /* stop Tns-alive and start Tns-test */ -------------- next part -------------- A non-text attachment was scrubbed... Name: pcap_trace_wireshark.pcap Type: application/octet-stream Size: 3675 bytes Desc: not available URL: -------------- next part -------------- --- gprs_sgsn_before_patch.c 2014-05-23 11:14:48.121829000 +0200 +++ gprs_sgsn_patch.c 2014-05-23 11:15:48.229829001 +0200 @@ -361,7 +361,7 @@ uint32_t ptmsi; restart: - ptmsi = rand(); + ptmsi = rand() | 0xc0000000; //because of GPRS IMSI ATTACH llist_for_each_entry(mm, &sgsn_mm_ctxts, list) { if (mm->p_tmsi == ptmsi) goto restart; From holger at freyther.de Fri May 23 11:16:50 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Fri, 23 May 2014 13:16:50 +0200 Subject: OsmoSGSN [PATCH], Network Service In-Reply-To: References: <20140517115033.GC14533@nataraja> Message-ID: <20140523111650.GE21550@xiaoyu.lan> On Fri, May 23, 2014 at 11:44:40AM +0200, Michal Grzn?r wrote: Hi, > And the problem was as I said in Imsi attach procedure new TLLI == new > allocated P-tmsi, and there was a problem that the function gprs_tmsi2tlli() > function there was not called and so I had to mask the upper bits in > function where the p-tmsi is allocated, there is also a pcap trace where > you can see it. Could you please elaborate of what/were (e.g. packet numbers) we can see "it" and what it should be instead? And please use "git diff" or preferable "git commit" and git format-patch. The "diff" you include is hand-written and sadly not usable because of this. And as written by Harald before. The place you patch is not correct. The method you patch should generate a unique P-TMSI. It might should mask some of the higher bits. But you need to look at the callers of this function if the tlli is not updated. e.g. in src/gprs/gprs_gmm.c you will see something like this: ctx->p_tmsi = sgsn_alloc_ptmsi(); #endif /* Even if there is no P-TMSI allocated, the MS will switch from * foreign TLLI to local TLLI */ ctx->tlli_new = gprs_tmsi2tlli(ctx->p_tmsi, TLLI_LOCAL); /* Inform LLC layer about new TLLI but keep old active */ gprs_llgmm_assign(ctx->llme, ctx->tlli, ctx->tlli_new, GPRS_ALGO_GEA0, NULL); So this call to gprs_tmsi2tlli will make sure that 0xc0000000 will be set. In fact I see two calls to sgsn_alloc_ptmsi and both of them do the above and assign the new tlli to the context. So please could you try to explain what you are trying to solve? holger From mihal.grznar at gmail.com Wed May 28 12:38:52 2014 From: mihal.grznar at gmail.com (=?UTF-8?Q?Michal_Grzn=C3=A1r?=) Date: Wed, 28 May 2014 14:38:52 +0200 Subject: OsmoSGSN [PATCH], Network Service In-Reply-To: <20140523111650.GE21550@xiaoyu.lan> References: <20140517115033.GC14533@nataraja> <20140523111650.GE21550@xiaoyu.lan> Message-ID: Hi, it wasn?t handly written diffs but here I send diff made by using git diff. And the problem you can see in packets with number 27-40 (especially see in number 30 you see there the old tlli and newly generated P-TMSI in message attach accept and in number 31 there is new TLLI which is the same as generated P-TMSI in previous message) and that is the problem I needed to solve, that the new TLLI was not LOCAL. regards Michal 2014-05-23 13:16 GMT+02:00 Holger Hans Peter Freyther : > On Fri, May 23, 2014 at 11:44:40AM +0200, Michal Grzn?r wrote: > > Hi, > > > And the problem was as I said in Imsi attach procedure new TLLI == new > > allocated P-tmsi, and there was a problem that the function > gprs_tmsi2tlli() > > function there was not called and so I had to mask the upper bits in > > function where the p-tmsi is allocated, there is also a pcap trace where > > you can see it. > > Could you please elaborate of what/were (e.g. packet numbers) we > can see "it" and what it should be instead? And please use "git diff" > or preferable "git commit" and git format-patch. The "diff" you include > is hand-written and sadly not usable because of this. > > And as written by Harald before. The place you patch is not correct. > The method you patch should generate a unique P-TMSI. It might should > mask some of the higher bits. But you need to look at the callers of > this function if the tlli is not updated. > > e.g. in src/gprs/gprs_gmm.c you will see something like this: > > ctx->p_tmsi = sgsn_alloc_ptmsi(); > #endif > > /* Even if there is no P-TMSI allocated, the MS will switch from > * foreign TLLI to local TLLI */ > ctx->tlli_new = gprs_tmsi2tlli(ctx->p_tmsi, TLLI_LOCAL); > > /* Inform LLC layer about new TLLI but keep old active */ > gprs_llgmm_assign(ctx->llme, ctx->tlli, ctx->tlli_new, > GPRS_ALGO_GEA0, NULL); > > So this call to gprs_tmsi2tlli will make sure that 0xc0000000 will > be set. In fact I see two calls to sgsn_alloc_ptmsi and both of them > do the above and assign the new tlli to the context. So please could > you try to explain what you are trying to solve? > > holger > > -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- diff --git a/home/michal/Plocha/gprs_sgsn_before_patch.c b/home/michal/Plocha/gp index 753d85f..f637a82 100644 --- a/home/michal/Plocha/gprs_sgsn_before_patch.c +++ b/home/michal/Plocha/gprs_sgsn_patch.c @@ -361,7 +361,7 @@ uint32_t sgsn_alloc_ptmsi(void) uint32_t ptmsi; restart: - ptmsi = rand(); + ptmsi = rand() | 0xc0000000; //because of GPRS IMSI ATTACH llist_for_each_entry(mm, &sgsn_mm_ctxts, list) { if (mm->p_tmsi == ptmsi) goto restart; -------------- next part -------------- diff --git a/home/michal/Plocha/gprs_ns_before_patch.c b/home/michal/Plocha/gprs_ns_patch.c index c939003..1bc965e 100644 --- a/home/michal/Plocha/gprs_ns_before_patch.c +++ b/home/michal/Plocha/gprs_ns_patch.c @@ -1217,16 +1217,14 @@ int gprs_ns_process_msg(struct gprs_ns_inst *nsi, struct msgb *msg, switch (nsh->pdu_type) { case NS_PDUT_ALIVE: - /* If we're dead and blocked and suddenly receive a - * NS-ALIVE out of the blue, we might have been re-started - * and should send a NS-RESET to make sure everything recovers - * fine. */ - -LOGP(DNS, LOGL_INFO, "Rx NS ALIVE\n"); -if ((*nsvc)->state == NSE_S_BLOCKED) - rc = gprs_ns_tx_reset((*nsvc), NS_CAUSE_PDU_INCOMP_PSTATE); - else - rc = gprs_ns_tx_alive_ack(*nsvc); + LOGP(DNS, LOGL_INFO, "Rx NS ALIVE\n"); + rc = gprs_ns_tx_alive_ack(*nsvc); + /*mark NS-VC as unblocked and active*/ + (*nsvc)->state = NSE_S_ALIVE; + (*nsvc)->remote_state = NSE_S_ALIVE; + /*Initiate TEST proc.: Send ALIVE_ACK and start timer*/ + rc = gprs_ns_tx_simple((*nsvc), NS_PDUT_ALIVE_ACK); + nsvc_start_timer((*nsvc), NSVC_TIMER_TNS_TEST); break; case NS_PDUT_ALIVE_ACK: /* stop Tns-alive and start Tns-test */ -------------- next part -------------- A non-text attachment was scrubbed... Name: pcap_trace_wireshark.pcap Type: application/octet-stream Size: 3675 bytes Desc: not available URL: From kluchnikovi at gmail.com Tue May 6 15:35:57 2014 From: kluchnikovi at gmail.com (Ivan Kluchnikov) Date: Tue, 6 May 2014 19:35:57 +0400 Subject: [PATCH 1/3] nitb/ctrl: Add ctrl command to get/set auth policy Message-ID: <1399390559-22655-1-git-send-email-kluchnikovi@gmail.com> --- openbsc/src/libbsc/bsc_ctrl_commands.c | 31 +++++++++++++++++++++++++++++++ openbsc/tests/ctrl_test_runner.py | 18 ++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/openbsc/src/libbsc/bsc_ctrl_commands.c b/openbsc/src/libbsc/bsc_ctrl_commands.c index 3759593..3cb77cc 100644 --- a/openbsc/src/libbsc/bsc_ctrl_commands.c +++ b/openbsc/src/libbsc/bsc_ctrl_commands.c @@ -66,6 +66,36 @@ CTRL_CMD_DEFINE_RANGE(net_mcc, "mcc", struct gsm_network, country_code, 1, 999); CTRL_CMD_VTY_STRING(net_short_name, "short-name", struct gsm_network, name_short); CTRL_CMD_VTY_STRING(net_long_name, "long-name", struct gsm_network, name_long); +static int verify_net_auth_policy(struct ctrl_cmd *cmd, const char *value, void *data) +{ + + if ((int)gsm_auth_policy_parse(value) < 0) { + return -1; + } + + return 0; +} + +static int get_net_auth_policy(struct ctrl_cmd *cmd, void *data) +{ + struct gsm_network *net = cmd->node; + cmd->reply = talloc_asprintf(cmd, "%s", gsm_auth_policy_name(net->auth_policy)); + if (!cmd->reply) { + cmd->reply = "OOM"; + return CTRL_CMD_ERROR; + } + return CTRL_CMD_REPLY; +} + +static int set_net_auth_policy(struct ctrl_cmd *cmd, void *data) +{ + struct gsm_network *net = cmd->node; + net->auth_policy = gsm_auth_policy_parse(cmd->value); + return get_net_auth_policy(cmd, data); +} + +CTRL_CMD_DEFINE(net_auth_policy, "auth-policy"); + static int verify_net_apply_config(struct ctrl_cmd *cmd, const char *v, void *d) { return 0; @@ -200,6 +230,7 @@ int bsc_base_ctrl_cmds_install(void) rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_mcc); rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_short_name); rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_long_name); + rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_auth_policy); rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_apply_config); rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_mcc_mnc_apply); diff --git a/openbsc/tests/ctrl_test_runner.py b/openbsc/tests/ctrl_test_runner.py index b50e93c..f24d52a 100644 --- a/openbsc/tests/ctrl_test_runner.py +++ b/openbsc/tests/ctrl_test_runner.py @@ -362,6 +362,24 @@ class TestCtrlNITB(TestCtrlBase): def ctrl_app(self): return (4249, "./src/osmo-nitb/osmo-nitb", "OsmoBSC", "nitb") + def testAuthPolicy(self): + policies = ['token', 'closed', 'accept-all'] + + for policy in policies: + r = self.do_set('auth-policy', policy) + self.assertEquals(r['mtype'], 'SET_REPLY') + self.assertEquals(r['var'], 'auth-policy') + self.assertEquals(r['value'], policy) + + r = self.do_get('auth-policy') + self.assertEquals(r['mtype'], 'GET_REPLY') + self.assertEquals(r['var'], 'auth-policy') + self.assertEquals(r['value'], policy) + + r = self.do_set('auth-policy', 'qwerty') + self.assertEquals(r['mtype'], 'ERROR') + self.assertEquals(r['error'], 'Value failed verification.') + def testSubscriberAddRemove(self): r = self.do_set('subscriber-modify-v1', '2620345,445566') self.assertEquals(r['mtype'], 'SET_REPLY') -- 1.7.9.5 From kluchnikovi at gmail.com Tue May 6 15:35:58 2014 From: kluchnikovi at gmail.com (Ivan Kluchnikov) Date: Tue, 6 May 2014 19:35:58 +0400 Subject: [PATCH 2/3] nitb/ctrl: Add ctrl command to get/set band In-Reply-To: <1399390559-22655-1-git-send-email-kluchnikovi@gmail.com> References: <1399390559-22655-1-git-send-email-kluchnikovi@gmail.com> Message-ID: <1399390559-22655-2-git-send-email-kluchnikovi@gmail.com> --- openbsc/src/libbsc/bsc_ctrl_commands.c | 33 ++++++++++++++++++++++++++++++++ openbsc/tests/ctrl_test_runner.py | 19 ++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/openbsc/src/libbsc/bsc_ctrl_commands.c b/openbsc/src/libbsc/bsc_ctrl_commands.c index 3cb77cc..bbd4fbd 100644 --- a/openbsc/src/libbsc/bsc_ctrl_commands.c +++ b/openbsc/src/libbsc/bsc_ctrl_commands.c @@ -183,6 +183,37 @@ oom: } CTRL_CMD_DEFINE(net_mcc_mnc_apply, "mcc-mnc-apply"); +/* BTS related commands below here */ +static int verify_bts_band(struct ctrl_cmd *cmd, const char *value, void *data) +{ + + if ((int)gsm_band_parse(value) < 0) { + return -1; + } + + return 0; +} + +static int get_bts_band(struct ctrl_cmd *cmd, void *data) +{ + struct gsm_bts *bts = cmd->node; + cmd->reply = talloc_asprintf(cmd, "%s", gsm_band_name(bts->band)); + if (!cmd->reply) { + cmd->reply = "OOM"; + return CTRL_CMD_ERROR; + } + return CTRL_CMD_REPLY; +} + +static int set_bts_band(struct ctrl_cmd *cmd, void *data) +{ + struct gsm_bts *bts = cmd->node; + bts->band = gsm_band_parse(cmd->value); + return get_bts_band(cmd, data); +} + +CTRL_CMD_DEFINE(bts_band, "band"); + /* TRX related commands below here */ CTRL_HELPER_GET_INT(trx_max_power, struct gsm_bts_trx, max_power_red); static int verify_trx_max_power(struct ctrl_cmd *cmd, const char *value, void *_data) @@ -234,6 +265,8 @@ int bsc_base_ctrl_cmds_install(void) rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_apply_config); rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_mcc_mnc_apply); + rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_band); + rc |= ctrl_cmd_install(CTRL_NODE_TRX, &cmd_trx_max_power); return rc; } diff --git a/openbsc/tests/ctrl_test_runner.py b/openbsc/tests/ctrl_test_runner.py index f24d52a..243ac0f 100644 --- a/openbsc/tests/ctrl_test_runner.py +++ b/openbsc/tests/ctrl_test_runner.py @@ -380,6 +380,25 @@ class TestCtrlNITB(TestCtrlBase): self.assertEquals(r['mtype'], 'ERROR') self.assertEquals(r['error'], 'Value failed verification.') + def testBtsBand(self): + bands = ['GSM450', 'GSM480', 'GSM750', 'GSM810', + 'GSM850', 'GSM900', 'DCS1800', 'PCS1900'] + + for band in bands: + r = self.do_set('bts.0.band', band) + self.assertEquals(r['mtype'], 'SET_REPLY') + self.assertEquals(r['var'], 'bts.0.band') + self.assertEquals(r['value'], band) + + r = self.do_get('bts.0.band') + self.assertEquals(r['mtype'], 'GET_REPLY') + self.assertEquals(r['var'], 'bts.0.band') + self.assertEquals(r['value'], band) + + r = self.do_set('bts.0.band', 'qwerty') + self.assertEquals(r['mtype'], 'ERROR') + self.assertEquals(r['error'], 'Value failed verification.') + def testSubscriberAddRemove(self): r = self.do_set('subscriber-modify-v1', '2620345,445566') self.assertEquals(r['mtype'], 'SET_REPLY') -- 1.7.9.5 From holger at freyther.de Wed May 7 07:19:37 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Wed, 7 May 2014 09:19:37 +0200 Subject: [PATCH 2/3] nitb/ctrl: Add ctrl command to get/set band In-Reply-To: <1399390559-22655-2-git-send-email-kluchnikovi@gmail.com> References: <1399390559-22655-1-git-send-email-kluchnikovi@gmail.com> <1399390559-22655-2-git-send-email-kluchnikovi@gmail.com> Message-ID: <20140507071937.GQ13870@xiaoyu.lan> On Tue, May 06, 2014 at 07:35:58PM +0400, Ivan Kluchnikov wrote: > + if ((int)gsm_band_parse(value) < 0) { > + return -1; > + } Same as with the previous patch. Either add a bottom element to to the gsm_band or return int from the method. But the above is the wrong thing to do. > + def testBtsBand(self): > + bands = ['GSM450', 'GSM480', 'GSM750', 'GSM810', > + 'GSM850', 'GSM900', 'DCS1800', 'PCS1900'] We handle PCS1800 or DCS900 as well. Maybe just make it 'public' and add these to the test. E.g. a matrix out of {'GSM','DCS', 'PCS'}x{450, 480, ...} for the test From kluchnikovi at gmail.com Tue May 6 15:35:59 2014 From: kluchnikovi at gmail.com (Ivan Kluchnikov) Date: Tue, 6 May 2014 19:35:59 +0400 Subject: [PATCH 3/3] nitb/ctrl: Add ctrl command to get/set arfcn In-Reply-To: <1399390559-22655-1-git-send-email-kluchnikovi@gmail.com> References: <1399390559-22655-1-git-send-email-kluchnikovi@gmail.com> Message-ID: <1399390559-22655-3-git-send-email-kluchnikovi@gmail.com> --- openbsc/src/libbsc/bsc_ctrl_commands.c | 2 ++ openbsc/tests/ctrl_test_runner.py | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/openbsc/src/libbsc/bsc_ctrl_commands.c b/openbsc/src/libbsc/bsc_ctrl_commands.c index bbd4fbd..d1edf29 100644 --- a/openbsc/src/libbsc/bsc_ctrl_commands.c +++ b/openbsc/src/libbsc/bsc_ctrl_commands.c @@ -253,6 +253,7 @@ static int set_trx_max_power(struct ctrl_cmd *cmd, void *_data) return get_trx_max_power(cmd, _data); } CTRL_CMD_DEFINE(trx_max_power, "max-power-reduction"); +CTRL_CMD_DEFINE_RANGE(trx_arfcn, "arfcn", struct gsm_bts_trx, arfcn, 0, 1023); int bsc_base_ctrl_cmds_install(void) { @@ -268,5 +269,6 @@ int bsc_base_ctrl_cmds_install(void) rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_band); rc |= ctrl_cmd_install(CTRL_NODE_TRX, &cmd_trx_max_power); + rc |= ctrl_cmd_install(CTRL_NODE_TRX, &cmd_trx_arfcn); return rc; } diff --git a/openbsc/tests/ctrl_test_runner.py b/openbsc/tests/ctrl_test_runner.py index 243ac0f..0dc9800 100644 --- a/openbsc/tests/ctrl_test_runner.py +++ b/openbsc/tests/ctrl_test_runner.py @@ -399,6 +399,21 @@ class TestCtrlNITB(TestCtrlBase): self.assertEquals(r['mtype'], 'ERROR') self.assertEquals(r['error'], 'Value failed verification.') + def testTrxArfcn(self): + r = self.do_set('bts.0.trx.0.arfcn', '51') + self.assertEquals(r['mtype'], 'SET_REPLY') + self.assertEquals(r['var'], 'bts.0.trx.0.arfcn') + self.assertEquals(r['value'], '51') + + r = self.do_get('bts.0.trx.0.arfcn') + self.assertEquals(r['mtype'], 'GET_REPLY') + self.assertEquals(r['var'], 'bts.0.trx.0.arfcn') + self.assertEquals(r['value'], '51') + + r = self.do_set('bts.0.trx.0.arfcn', '3000') + self.assertEquals(r['mtype'], 'ERROR') + self.assertEquals(r['error'], 'Input not within the range') + def testSubscriberAddRemove(self): r = self.do_set('subscriber-modify-v1', '2620345,445566') self.assertEquals(r['mtype'], 'SET_REPLY') -- 1.7.9.5 From holger at freyther.de Wed May 7 07:26:40 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Wed, 7 May 2014 09:26:40 +0200 Subject: [PATCH 3/3] nitb/ctrl: Add ctrl command to get/set arfcn In-Reply-To: <1399390559-22655-3-git-send-email-kluchnikovi@gmail.com> References: <1399390559-22655-1-git-send-email-kluchnikovi@gmail.com> <1399390559-22655-3-git-send-email-kluchnikovi@gmail.com> Message-ID: <20140507072640.GR13870@xiaoyu.lan> On Tue, May 06, 2014 at 07:35:59PM +0400, Ivan Kluchnikov wrote: Hi again, > +CTRL_CMD_DEFINE_RANGE(trx_arfcn, "arfcn", struct gsm_bts_trx, arfcn, 0, 1023); Please look at cfg_trx_arfcn_cmd in src/libbsc/bsc_vty.c. There are plenty of "FIXME" in the code and they all apply here. There are two separate issues that your patch is touching. 1.) Align VTY and CTRL command. My approach so far was to move the "handling" into a common method that is used by CTRL/VTY. 2.) The general question of "when" to apply the configuration. For some commands it is immediate, for some comments it is after a BTS is bootstrapped again and for some it requires a re-start of the NITB application. 3.) Make it impossible to configure a "broken" system. For your code and the VTY command it is possible to create and later save/write a config that will not be parsed on re-start. So this patch at least needs to do: * Make the CTRL and VTY share a routine to "set" the ARFCN * Move the FIXMEs into this routine * Verify that the BAND + ARFCN would be compatible (so we would still have three FIXMEs left). cheers holger From holger at freyther.de Wed May 7 07:16:36 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Wed, 7 May 2014 09:16:36 +0200 Subject: [PATCH 1/3] nitb/ctrl: Add ctrl command to get/set auth policy In-Reply-To: <1399390559-22655-1-git-send-email-kluchnikovi@gmail.com> References: <1399390559-22655-1-git-send-email-kluchnikovi@gmail.com> Message-ID: <20140507071636.GP13870@xiaoyu.lan> On Tue, May 06, 2014 at 07:35:57PM +0400, Ivan Kluchnikov wrote: hi, > + if ((int)gsm_auth_policy_parse(value) < 0) { > + return -1; > + } 1.) Coding-Style. 2.) The (int) cast is fishy. Most likely even undefined C usage. We have a int(-EINVAL) -> enum -> int conversion here. Add an invalid element to the enum, change the implementation to compare to -EINVAL... Then your verify call becomes a simple one liner and comparison against the invalid element. > + def testAuthPolicy(self): > + r = self.do_set('auth-policy', 'qwerty') > + self.assertEquals(r['mtype'], 'ERROR') > + self.assertEquals(r['error'], 'Value failed verification.') Check that the previous thing has not been changed. :) From koue at chaosophia.net Wed May 7 08:00:54 2014 From: koue at chaosophia.net (Nikola Kolev) Date: 07 May 2014 11:00:54 +0300 Subject: [PATCH] openbsc/include/openbsc/bsc_msc.h: FreeBSD uses POSIX netinet/in.h for representing socket addresses data types Message-ID: FreeBSD uses POSIX netinet/in.h for representing socket addresses data types. The header file is available on Linux also. -- Nikola -------------- next part -------------- A non-text attachment was scrubbed... Name: openbsc-freebsd-bsc_msc-patch.diff Type: application/octet-stream Size: 379 bytes Desc: openbsc-freebsd-bsc_msc-patch.diff URL: From koue at chaosophia.net Wed May 7 08:04:07 2014 From: koue at chaosophia.net (Nikola Kolev) Date: 07 May 2014 11:04:07 +0300 Subject: [PATCH] openbsc/src/ipaccess/ipaccess-find.c: FreeBSD uses IP_SENDIF as analog of the Linux socket option SO_BINDTODEVICE Message-ID: IP_SENDIF is broadly an analogue of the Linux socket option SO_BINDTODEVICE. It is used to bypass the traditional BSD source interface selection logic. It is a sledgehammer hack used to output datagrams on a specific interface which may not yet have an address, e.g. for DHCP. -- Nikola -------------- next part -------------- A non-text attachment was scrubbed... Name: openbsc-freebsd-ipaccess-find-patch.diff Type: application/octet-stream Size: 522 bytes Desc: openbsc-freebsd-ipaccess-find-patch.diff URL: From koue at chaosophia.net Thu May 8 09:44:47 2014 From: koue at chaosophia.net (Nikola Kolev) Date: Thu, 8 May 2014 12:44:47 +0300 Subject: [PATCH 1/2] FreeBSD uses POSIX netinet/in.h for representing socket addresses data types. Message-ID: <1399542287-60444-1-git-send-email-koue@chaosophia.net> --- openbsc/include/openbsc/bsc_msc.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openbsc/include/openbsc/bsc_msc.h b/openbsc/include/openbsc/bsc_msc.h index 0adbd26..ee867af 100644 --- a/openbsc/include/openbsc/bsc_msc.h +++ b/openbsc/include/openbsc/bsc_msc.h @@ -22,6 +22,10 @@ #ifndef BSC_MSC_H #define BSC_MSC_H +#ifdef __FreeBSD__ +#include +#endif + #include #include -- 1.9.2 From koue at chaosophia.net Thu May 8 09:45:20 2014 From: koue at chaosophia.net (Nikola Kolev) Date: Thu, 8 May 2014 12:45:20 +0300 Subject: [PATCH 2/2] In BSD IP_RECVIF can be used as analogue of the Linux socket option SO_BINDTODEVICE. Message-ID: <1399542320-60500-1-git-send-email-koue@chaosophia.net> --- openbsc/src/ipaccess/ipaccess-find.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openbsc/src/ipaccess/ipaccess-find.c b/openbsc/src/ipaccess/ipaccess-find.c index bb9819e..c8de157 100644 --- a/openbsc/src/ipaccess/ipaccess-find.c +++ b/openbsc/src/ipaccess/ipaccess-find.c @@ -41,8 +41,13 @@ static int udp_sock(const char *ifname) return fd; if (ifname) { +#ifdef __FreeBSD__ + rc = setsockopt(fd, SOL_SOCKET, IP_RECVIF, ifname, + strlen(ifname)); +#else rc = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname)); +#endif if (rc < 0) goto err; } -- 1.9.2 From tom at tsou.cc Thu May 8 17:41:17 2014 From: tom at tsou.cc (Thomas Tsou) Date: Thu, 8 May 2014 13:41:17 -0400 Subject: [osmo-bts PATCH] TRX: Remove extra TCH/HS puncturing value Message-ID: <20140508174117.GA28072@phenom.hsd1.va.comcast.net> 3GPP TS 05.03 "Channel coding" specifies the puncturing matrix (1,0,1) for class 1 information bits and tail bits valued u(0) to u(103) for a maximum puncturing index of 311. The puncturing index 313 exceeds the maximum index and causes osmo_conv_get_output_length() to output the improper length of 210 instead of 211. Signed-off-by: Thomas Tsou --- src/osmo-bts-trx/gsm0503_conv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/osmo-bts-trx/gsm0503_conv.c b/src/osmo-bts-trx/gsm0503_conv.c index 2a814ca..dc50e6c 100644 --- a/src/osmo-bts-trx/gsm0503_conv.c +++ b/src/osmo-bts-trx/gsm0503_conv.c @@ -139,7 +139,7 @@ static const int conv_tch_hr_puncture[] = { 253, 256, 259, 262, 265, 268, 271, 274, 277, 280, 283, /* Tail bits */ - 295, 298, 301, 304, 307, 310, 313, + 295, 298, 301, 304, 307, 310, /* End */ -1, -- 1.9.0 From andreas at eversberg.eu Thu May 8 18:35:51 2014 From: andreas at eversberg.eu (Andreas Eversberg) Date: Thu, 08 May 2014 20:35:51 +0200 Subject: [osmo-bts PATCH] TRX: Remove extra TCH/HS puncturing value In-Reply-To: <20140508174117.GA28072@phenom.hsd1.va.comcast.net> References: <20140508174117.GA28072@phenom.hsd1.va.comcast.net> Message-ID: <536BCE87.1020301@eversberg.eu> Thomas Tsou wrote: > 3GPP TS 05.03 "Channel coding" specifies the puncturing matrix (1,0,1) > for class 1 information bits and tail bits valued u(0) to u(103) for a > maximum puncturing index of 311. The puncturing index 313 exceeds the > maximum index and causes osmo_conv_get_output_length() to output the > improper length of 210 instead of 211. > > Signed-off-by: Thomas Tsou > --- > src/osmo-bts-trx/gsm0503_conv.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/src/osmo-bts-trx/gsm0503_conv.c b/src/osmo-bts-trx/gsm0503_conv.c > index 2a814ca..dc50e6c 100644 > --- a/src/osmo-bts-trx/gsm0503_conv.c > +++ b/src/osmo-bts-trx/gsm0503_conv.c > @@ -139,7 +139,7 @@ static const int conv_tch_hr_puncture[] = { > 253, 256, 259, 262, 265, 268, 271, 274, 277, 280, 283, > > /* Tail bits */ > - 295, 298, 301, 304, 307, 310, 313, > + 295, 298, 301, 304, 307, 310, > > /* End */ > -1, hi thomas, thanx for the patch. i blindly applied it, since it look reasonable but i have no time to test/review it. it is in the branch jolly/trx_rebased. please let me know if it works or not. did you test it with a half rate v1 call? best regards, andreas From tom at tsou.cc Thu May 8 19:04:46 2014 From: tom at tsou.cc (Tom Tsou) Date: Thu, 8 May 2014 15:04:46 -0400 Subject: [osmo-bts PATCH] TRX: Remove extra TCH/HS puncturing value In-Reply-To: <536BCE87.1020301@eversberg.eu> References: <20140508174117.GA28072@phenom.hsd1.va.comcast.net> <536BCE87.1020301@eversberg.eu> Message-ID: On Thu, May 8, 2014 at 2:35 PM, Andreas Eversberg wrote: > thanx for the patch. i blindly applied it, since it look reasonable but > i have no time to test/review it. it is in the branch jolly/trx_rebased. > please let me know if it works or not. did you test it with a half rate > v1 call? I tested it with the libosmocore 'make check' code. I did not place any calls. The length at the encoder output was correct. Only the length when calling osmo_conv_get_output_length() on the code was in error. -TT From ottawa712 at gmail.com Fri May 9 13:38:31 2014 From: ottawa712 at gmail.com (ottawa ottawa) Date: Fri, 9 May 2014 09:38:31 -0400 Subject: PDP deactivation on a particular cell phone--can anybody reply please Message-ID: Hi Gurus I am using OpenBSC/GPRS with nanoBTS. Thanks everybody for the great work. GPRS works well with many cell phone, but for particular cell phone its not working. I saw Olaf Schulz posting (subject: GPRS problems with Nokia Handsets dated 4th May 2012). Saw his pcap file and mine is similar too. Frank Mass suggested a patch to overcome this problem in his posting (subject gprs_llc.c foreighn TLLI is stored but not searched, dated 30 April 2012). I have implemented that patch but still not working. Can any body suggest something. Please find the osmo-sgsn trace <0011> gprs_bssgp.c:376 BSSGP TLLI=0xabfafd41 Rx UPLINK-UNITDATA <0012> gprs_llc.c:551 LLC SAPI=1 C FCS=0x76d7d9CMD=UI DATA <0012> gprs_llc.c:95 TLLI 0xabfafd41 is foreign, converting to local TLLI 0xebfafd41 <0012> gprs_llc.c:245 LLC RX: unknown TLLI 0xabfafd41, creating LLME on the fly <0011> gprs_bssgp.c:753 BSSGP BVCI=2 Rx Flow Control BVC <0011> gprs_bssgp.c:376 BSSGP TLLI=0xabfafd41 Rx UPLINK-UNITDATA <0012> gprs_llc.c:551 LLC SAPI=1 R FCS=0x57768eCMD=XID DATA <0011> gprs_bssgp.c:376 BSSGP TLLI=0xabfafd41 Rx UPLINK-UNITDATA <0012> gprs_llc.c:551 LLC SAPI=1 C FCS=0x9ab10aCMD=UI DATA <0012> gprs_llc.c:598 TLLI=abfafd41 dropping UI, N(U=0) not in window V(URV(UR:3). <0011> gprs_bssgp.c:753 BSSGP BVCI=2 Rx Flow Control BVC <0011> gprs_bssgp.c:753 BSSGP BVCI=2 Rx Flow Control BVC <0011> gprs_bssgp.c:376 BSSGP TLLI=0x7d3b00c1 Rx UPLINK-UNITDATA <0012> gprs_llc.c:551 LLC SAPI=1 C FCS=0xfd5011CMD=UI DATA <0012> gprs_llc.c:245 LLC RX: unknown TLLI 0x7d3b00c1, creating LLME on the fly <0011> gprs_bssgp.c:753 BSSGP BVCI=2 Rx Flow Control BVC <0011> gprs_bssgp.c:376 BSSGP TLLI=0x7d3b00c1 Rx UPLINK-UNITDATA <0012> gprs_llc.c:551 LLC SAPI=1 C FCS=0x11fb2fCMD=UI DATA <0011> gprs_bssgp.c:376 BSSGP TLLI=0x7d3b00c1 Rx UPLINK-UNITDATA <0012> gprs_llc.c:551 LLC SAPI=1 C FCS=0xea1c55CMD=UI DATA <0011> gprs_bssgp.c:753 BSSGP BVCI=2 Rx Flow Control BVC <0011> gprs_bssgp.c:753 BSSGP BVCI=2 Rx Flow Control BVC <0011> gprs_bssgp.c:376 BSSGP TLLI=0xe23c0990 Rx UPLINK-UNITDATA <0012> gprs_llc.c:551 LLC SAPI=1 C FCS=0x2a6a81CMD=UI DATA <000f> sgsn_libgtp.c:126 Create PDP Context <000f> sgsn_libgtp.c:379 libgtp cb_conf(type=16, cause=128, pdp=0x7feafc152320, cbp=0x6bcf50) <000f> sgsn_libgtp.c:265 Received CREATE PDP CTX CONF, cause=128(Request accepted) <0013> gprs_sndcp.c:297 SNSM-ACTIVATE.ind (lle=0x6bbe60 TLLI=e23c0990, SAPI=3, NSAPI=5) <0011> gprs_bssgp.c:753 BSSGP BVCI=2 Rx Flow Control BVC <0011> gprs_bssgp.c:753 BSSGP BVCI=2 Rx Flow Control BVC <0011> gprs_bssgp.c:753 BSSGP BVCI=2 Rx Flow Control BVC <0011> gprs_bssgp.c:376 BSSGP TLLI=0xe23c0990 Rx UPLINK-UNITDATA <0012> gprs_llc.c:551 LLC SAPI=1 C FCS=0x819789CMD=UI DATA <000f> sgsn_libgtp.c:212 Delete PDP Context <000f> sgsn_libgtp.c:402 PDP Context was deleted <000f> sgsn_libgtp.c:379 libgtp cb_conf(type=20, cause=128, pdp=(nil), cbp=0x6bcf50) <000f> sgsn_libgtp.c:321 Received DELETE PDP CTX CONF, cause=128(Request accepted) <0013> gprs_sndcp.c:320 SNSM-DEACTIVATE.ind (lle=0x6bbe60, TLLI=e23c0990, SAPI=3, NSAPI=5) John -------------- next part -------------- An HTML attachment was scrubbed... URL: From jerlbeck at sysmocom.de Fri May 9 15:25:36 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Fri, 9 May 2014 17:25:36 +0200 Subject: [PATCH] ctrl: Fix handling of missing replies Message-ID: <1399649136-15337-1-git-send-email-jerlbeck@sysmocom.de> Currently, if a CTRL method does not set the reply, an error is logged ("cmd->reply has not been set"). This patch changes the logging level from ERROR to INFO. The logging is now only done, when the retry has not been set and the implementation returns CTRL_CMD_ERROR or the GET has been used. This means, every time a error is signalled or GET is used, the retry field shall be set. Some missing reply texts in error cases are also added. Ticket: OW#1177 Sponsored-by: On-Waves ehf --- openbsc/src/libbsc/bsc_ctrl_lookup.c | 11 ++++++++--- openbsc/src/osmo-bsc/osmo_bsc_ctrl.c | 4 +++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/openbsc/src/libbsc/bsc_ctrl_lookup.c b/openbsc/src/libbsc/bsc_ctrl_lookup.c index 338fb11..dced8bd 100644 --- a/openbsc/src/libbsc/bsc_ctrl_lookup.c +++ b/openbsc/src/libbsc/bsc_ctrl_lookup.c @@ -150,10 +150,15 @@ int bsc_ctrl_cmd_handle(struct ctrl_cmd *cmd, void *data) err: if (!cmd->reply) { - LOGP(DCTRL, LOGL_ERROR, "cmd->reply has not been set.\n"); - if (ret == CTRL_CMD_ERROR) + if (ret == CTRL_CMD_ERROR) { cmd->reply = "An error has occured."; - else + LOGP(DCTRL, LOGL_NOTICE, + "cmd->reply has not been set (ERROR).\n"); + } else if (cmd->type == CTRL_TYPE_GET) { + LOGP(DCTRL, LOGL_NOTICE, + "cmd->reply has not been set (GET).\n"); + cmd->reply = ""; + } else cmd->reply = "Command has been handled."; } diff --git a/openbsc/src/osmo-bsc/osmo_bsc_ctrl.c b/openbsc/src/osmo-bsc/osmo_bsc_ctrl.c index e32218d..3cc704b 100644 --- a/openbsc/src/osmo-bsc/osmo_bsc_ctrl.c +++ b/openbsc/src/osmo-bsc/osmo_bsc_ctrl.c @@ -72,6 +72,7 @@ static int get_msc_connection_status(struct ctrl_cmd *cmd, void *data) static int set_msc_connection_status(struct ctrl_cmd *cmd, void *data) { + cmd->reply = "Set is unimplemented"; return CTRL_CMD_ERROR; } @@ -128,6 +129,7 @@ static int get_bts_connection_status(struct ctrl_cmd *cmd, void *data) static int set_bts_connection_status(struct ctrl_cmd *cmd, void *data) { + cmd->reply = "Set is unimplemented"; return CTRL_CMD_ERROR; } @@ -522,7 +524,7 @@ static int get_bts_rf_state(struct ctrl_cmd *cmd, void *data) static int set_bts_rf_state(struct ctrl_cmd *cmd, void *data) { - cmd->reply = "set is unimplemented"; + cmd->reply = "Set is unimplemented"; return CTRL_CMD_ERROR; } -- 1.7.9.5 From holger at freyther.de Wed May 14 05:25:14 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Wed, 14 May 2014 07:25:14 +0200 Subject: [PATCH] ctrl: Fix handling of missing replies In-Reply-To: <1399649136-15337-1-git-send-email-jerlbeck@sysmocom.de> References: <1399649136-15337-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <20140514052514.GF26057@xiaoyu.lan> On Fri, May 09, 2014 at 05:25:36PM +0200, Jacob Erlbeck wrote: Good Morning, > Currently, if a CTRL method does not set the reply, an error is > logged ("cmd->reply has not been set"). hmm. I would like to see some more reflection here. The "reply" not being set being an ERROR was done by you, now the NAT might have a legetimate use-case for not setting a reply. I don't see this being reflected in the commit message. > if (!cmd->reply) { > - LOGP(DCTRL, LOGL_ERROR, "cmd->reply has not been set.\n"); > - if (ret == CTRL_CMD_ERROR) > + if (ret == CTRL_CMD_ERROR) { > cmd->reply = "An error has occured."; > - else > + LOGP(DCTRL, LOGL_NOTICE, > + "cmd->reply has not been set (ERROR).\n"); > + } else if (cmd->type == CTRL_TYPE_GET) { > + LOGP(DCTRL, LOGL_NOTICE, > + "cmd->reply has not been set (GET).\n"); > + cmd->reply = ""; > + } else > cmd->reply = "Command has been handled."; I am not convinced. The NAT will still generate these messages on the stdout but there is nothing to be fixed?! To make the actual log message more useful one should output the name of command. :) > static int set_msc_connection_status(struct ctrl_cmd *cmd, void *data) > { > + cmd->reply = "Set is unimplemented"; > return CTRL_CMD_ERROR; > } Hmm, "unimplemented" somehow indicates that we would know what to implement. E.g. if we take a look at verify_msc_connection_status I claim that "msc_connection_status" is just a read-only attribute. > > @@ -128,6 +129,7 @@ static int get_bts_connection_status(struct ctrl_cmd *cmd, void *data) > > static int set_bts_connection_status(struct ctrl_cmd *cmd, void *data) > { > + cmd->reply = "Set is unimplemented"; > return CTRL_CMD_ERROR; > } The same here. It is read-only. > > @@ -522,7 +524,7 @@ static int get_bts_rf_state(struct ctrl_cmd *cmd, void *data) > > static int set_bts_rf_state(struct ctrl_cmd *cmd, void *data) > { > - cmd->reply = "set is unimplemented"; > + cmd->reply = "Set is unimplemented"; > return CTRL_CMD_ERROR; > } It should probably be read-only. I will introduce a CTRL_CMD_DEFINE for read-only commands but the actual issue is still there. cheers holger From jerlbeck at sysmocom.de Thu May 15 11:04:14 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Thu, 15 May 2014 13:04:14 +0200 Subject: [PATCH] ctrl: Fix handling of missing replies In-Reply-To: <1399649136-15337-1-git-send-email-jerlbeck@sysmocom.de> References: <1399649136-15337-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1400151854-2048-1-git-send-email-jerlbeck@sysmocom.de> Currently, if a CTRL method does not set the reply, an error is logged ("cmd->reply has not been set"). It even complains when the function implementing the command returns CTRL_CMD_HANDLED, where a reply text is not needed. This patch changes the logging level from ERROR to NOTICE. The logging is now only done, when the retry has not been set and the implementation returns either CTRL_CMD_ERROR or CTRL_CMD_REPLY. So in these cases the reply field must be set. This fixes the generation of log messages when doing NAT ctrl command forwarding. Ticket: OW#1177 Sponsored-by: On-Waves ehf --- openbsc/src/libbsc/bsc_ctrl_lookup.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/openbsc/src/libbsc/bsc_ctrl_lookup.c b/openbsc/src/libbsc/bsc_ctrl_lookup.c index 338fb11..3a3df9c 100644 --- a/openbsc/src/libbsc/bsc_ctrl_lookup.c +++ b/openbsc/src/libbsc/bsc_ctrl_lookup.c @@ -150,11 +150,19 @@ int bsc_ctrl_cmd_handle(struct ctrl_cmd *cmd, void *data) err: if (!cmd->reply) { - LOGP(DCTRL, LOGL_ERROR, "cmd->reply has not been set.\n"); - if (ret == CTRL_CMD_ERROR) + if (ret == CTRL_CMD_ERROR) { cmd->reply = "An error has occured."; - else + LOGP(DCTRL, LOGL_NOTICE, + "%s: cmd->reply has not been set (ERROR).\n", + cmd->variable); + } else if (ret == CTRL_CMD_REPLY) { + LOGP(DCTRL, LOGL_NOTICE, + "%s: cmd->reply has not been set (type = %d).\n", + cmd->variable, cmd->type); + cmd->reply = ""; + } else { cmd->reply = "Command has been handled."; + } } if (ret == CTRL_CMD_ERROR) -- 1.7.9.5 From holger at freyther.de Thu May 15 19:24:58 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Thu, 15 May 2014 21:24:58 +0200 Subject: [PATCH] ctrl: Fix handling of missing replies In-Reply-To: <1400151854-2048-1-git-send-email-jerlbeck@sysmocom.de> References: <1399649136-15337-1-git-send-email-jerlbeck@sysmocom.de> <1400151854-2048-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <20140515192458.GJ26903@xiaoyu.lan> On Thu, May 15, 2014 at 01:04:14PM +0200, Jacob Erlbeck wrote: > Currently, if a CTRL method does not set the reply, an error is > logged ("cmd->reply has not been set"). It even complains when the > function implementing the command returns CTRL_CMD_HANDLED, where > a reply text is not needed. > > This patch changes the logging level from ERROR to NOTICE. The logging > is now only done, when the retry has not been set and the ^^^^^^ <- reply? > implementation returns either CTRL_CMD_ERROR or CTRL_CMD_REPLY. So > in these cases the reply field must be set. > - if (ret == CTRL_CMD_ERROR) > + if (ret == CTRL_CMD_ERROR) { > cmd->reply = "An error has occured."; > - else > + LOGP(DCTRL, LOGL_NOTICE, > + "%s: cmd->reply has not been set (ERROR).\n", > + cmd->variable); > + } else if (ret == CTRL_CMD_REPLY) { > + LOGP(DCTRL, LOGL_NOTICE, > + "%s: cmd->reply has not been set (type = %d).\n", > + cmd->variable, cmd->type); > + cmd->reply = ""; > + } else { > cmd->reply = "Command has been handled."; Is using a switch/case better here? So for CTRL_CMD_HANDLED the "Command has been handled" will be set? From jerlbeck at sysmocom.de Mon May 19 07:38:25 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Mon, 19 May 2014 09:38:25 +0200 Subject: [PATCH] ctrl: Fix handling of missing replies In-Reply-To: <20140515192458.GJ26903@xiaoyu.lan> References: <1399649136-15337-1-git-send-email-jerlbeck@sysmocom.de> <1400151854-2048-1-git-send-email-jerlbeck@sysmocom.de> <20140515192458.GJ26903@xiaoyu.lan> Message-ID: <5379B4F1.8080701@sysmocom.de> On 15.05.2014 21:24, Holger Hans Peter Freyther wrote: > On Thu, May 15, 2014 at 01:04:14PM +0200, Jacob Erlbeck wrote: >> Currently, if a CTRL method does not set the reply, an error is >> logged ("cmd->reply has not been set"). It even complains when the >> function implementing the command returns CTRL_CMD_HANDLED, where >> a reply text is not needed. >> >> This patch changes the logging level from ERROR to NOTICE. The logging >> is now only done, when the retry has not been set and the > > ^^^^^^ <- reply? Yes, of course, thanks. > >> implementation returns either CTRL_CMD_ERROR or CTRL_CMD_REPLY. So >> in these cases the reply field must be set. > >> - if (ret == CTRL_CMD_ERROR) >> + if (ret == CTRL_CMD_ERROR) { >> cmd->reply = "An error has occured."; >> - else >> + LOGP(DCTRL, LOGL_NOTICE, >> + "%s: cmd->reply has not been set (ERROR).\n", >> + cmd->variable); >> + } else if (ret == CTRL_CMD_REPLY) { >> + LOGP(DCTRL, LOGL_NOTICE, >> + "%s: cmd->reply has not been set (type = %d).\n", >> + cmd->variable, cmd->type); >> + cmd->reply = ""; >> + } else { >> cmd->reply = "Command has been handled."; > > Is using a switch/case better here? So for CTRL_CMD_HANDLED the > "Command has been handled" will be set? Yes, I'd like to use a switch here, too. But CTRL_CMD_* are not enums and CTRL_CMD_ERROR is defined to -1, which I don't want to use as case constant. I'd rather turn CTRL_CMD_* into an enum and replace if's by switches in another patch. Jacob -- - Jacob Erlbeck http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Schivelbeiner Str. 5 * 10439 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte From jerlbeck at sysmocom.de Mon May 12 10:38:57 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Mon, 12 May 2014 12:38:57 +0200 Subject: [PATCH 01/11] mgcp: Add callbacks for payload processing Message-ID: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> This patch adds the callbacks rtp_processing_cb and setup_rtp_processing_cb to mgcp_config to support arbitrary RTP payload processing. Sponsored-by: On-Waves ehf --- openbsc/include/openbsc/mgcp.h | 10 +++++++++ openbsc/include/openbsc/mgcp_internal.h | 8 ++++++++ openbsc/src/libmgcp/mgcp_network.c | 20 +++++++++++++++--- openbsc/src/libmgcp/mgcp_protocol.c | 34 ++++++++++++++++++++++++++++++- 4 files changed, 68 insertions(+), 4 deletions(-) diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h index 1d74078..6ba0769 100644 --- a/openbsc/include/openbsc/mgcp.h +++ b/openbsc/include/openbsc/mgcp.h @@ -65,6 +65,7 @@ static inline int rtp_calculate_port(int multiplex, int base) struct mgcp_endpoint; struct mgcp_config; struct mgcp_trunk_config; +struct mgcp_rtp_end; #define MGCP_ENDP_CRCX 1 #define MGCP_ENDP_DLCX 2 @@ -86,6 +87,11 @@ typedef int (*mgcp_policy)(struct mgcp_trunk_config *cfg, int endpoint, int stat typedef int (*mgcp_reset)(struct mgcp_trunk_config *cfg); typedef int (*mgcp_rqnt)(struct mgcp_endpoint *endp, char tone); +typedef int (*mgcp_processing)(struct mgcp_rtp_end *dst_end, + char *data, int *len, int buf_size); +typedef int (*mgcp_processing_setup)(struct mgcp_endpoint *endp, + struct mgcp_rtp_end *dst_end, + struct mgcp_rtp_end *src_end); #define PORT_ALLOC_STATIC 0 #define PORT_ALLOC_DYNAMIC 1 @@ -156,6 +162,10 @@ struct mgcp_config { struct in_addr transcoder_in; int transcoder_remote_base; + /* RTP processing */ + mgcp_processing rtp_processing_cb; + mgcp_processing_setup setup_rtp_processing_cb; + struct osmo_wqueue gw_fd; struct mgcp_port_range bts_ports; diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h index 9b97165..56c280d 100644 --- a/openbsc/include/openbsc/mgcp_internal.h +++ b/openbsc/include/openbsc/mgcp_internal.h @@ -91,6 +91,7 @@ struct mgcp_rtp_end { /* RTP patching */ int force_constant_ssrc; /* -1: always, 0: don't, 1: once */ int force_aligned_timing; + void *rtp_process_data; /* * Each end has a socket... @@ -197,5 +198,12 @@ void mgcp_state_calc_loss(struct mgcp_rtp_state *s, struct mgcp_rtp_end *, uint32_t *expected, int *loss); uint32_t mgcp_state_calc_jitter(struct mgcp_rtp_state *); +/* payload processing default functions */ +int mgcp_rtp_processing_default(struct mgcp_rtp_end *dst_end, + char *data, int *len, int buf_size); + +int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp, + struct mgcp_rtp_end *dst_end, + struct mgcp_rtp_end *src_end); #endif diff --git a/openbsc/src/libmgcp/mgcp_network.c b/openbsc/src/libmgcp/mgcp_network.c index 8a5656a..4d1ad35 100644 --- a/openbsc/src/libmgcp/mgcp_network.c +++ b/openbsc/src/libmgcp/mgcp_network.c @@ -77,6 +77,7 @@ struct rtp_hdr { #define RTP_SEQ_MOD (1 << 16) #define RTP_MAX_DROPOUT 3000 #define RTP_MAX_MISORDER 100 +#define RTP_BUF_SIZE 4096 enum { @@ -347,6 +348,18 @@ static int align_rtp_timestamp_offset(struct mgcp_endpoint *endp, return timestamp_error; } +int mgcp_rtp_processing_default(struct mgcp_rtp_end *dst_end, + char *data, int *len, int buf_size) +{ + return 0; +} + +int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp, + struct mgcp_rtp_end *dst_end, + struct mgcp_rtp_end *src_end) +{ + return 0; +} /** * The RFC 3550 Appendix A assumes there are multiple sources but @@ -597,6 +610,7 @@ static int mgcp_send(struct mgcp_endpoint *endp, int dest, int is_rtp, rtp_end->dropped_packets += 1; else if (is_rtp) { mgcp_patch_and_count(endp, rtp_state, rtp_end, addr, buf, rc); + endp->cfg->rtp_processing_cb(rtp_end, buf, &rc, RTP_BUF_SIZE); forward_data(rtp_end->rtp.fd, &endp->taps[tap_idx], buf, rc); return mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr, @@ -635,7 +649,7 @@ static int receive_from(struct mgcp_endpoint *endp, int fd, struct sockaddr_in * static int rtp_data_net(struct osmo_fd *fd, unsigned int what) { - char buf[4096]; + char buf[RTP_BUF_SIZE]; struct sockaddr_in addr; struct mgcp_endpoint *endp; int rc, proto; @@ -719,7 +733,7 @@ static void discover_bts(struct mgcp_endpoint *endp, int proto, struct sockaddr_ static int rtp_data_bts(struct osmo_fd *fd, unsigned int what) { - char buf[4096]; + char buf[RTP_BUF_SIZE]; struct sockaddr_in addr; struct mgcp_endpoint *endp; int rc, proto; @@ -781,7 +795,7 @@ static int rtp_data_bts(struct osmo_fd *fd, unsigned int what) static int rtp_data_transcoder(struct mgcp_rtp_end *end, struct mgcp_endpoint *_endp, int dest, struct osmo_fd *fd) { - char buf[4096]; + char buf[RTP_BUF_SIZE]; struct sockaddr_in addr; struct mgcp_config *cfg; int rc, proto; diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c index 5c88c9d..0f8614c 100644 --- a/openbsc/src/libmgcp/mgcp_protocol.c +++ b/openbsc/src/libmgcp/mgcp_protocol.c @@ -107,6 +107,8 @@ static struct msgb *handle_noti_req(struct mgcp_parse_data *data); static void create_transcoder(struct mgcp_endpoint *endp); static void delete_transcoder(struct mgcp_endpoint *endp); +static void setup_rtp_processing(struct mgcp_endpoint *endp); + static int mgcp_analyze_header(struct mgcp_parse_data *parse, char *data); static uint32_t generate_call_id(struct mgcp_config *cfg) @@ -827,8 +829,10 @@ mgcp_header_done: endp->bts_end.payload_type = tcfg->audio_payload; endp->bts_end.fmtp_extra = talloc_strdup(tcfg->endpoints, tcfg->audio_fmtp_extra); - if (have_sdp) + if (have_sdp) { parse_sdp_data(&endp->net_end, p); + setup_rtp_processing(endp); + } /* policy CB */ if (p->cfg->policy_cb) { @@ -929,6 +933,8 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p) set_local_cx_options(endp->tcfg->endpoints, &endp->local_options, local_options); + setup_rtp_processing(endp); + /* policy CB */ if (p->cfg->policy_cb) { int rc; @@ -1169,6 +1175,9 @@ struct mgcp_config *mgcp_config_alloc(void) cfg->bts_ports.base_port = RTP_PORT_DEFAULT; cfg->net_ports.base_port = RTP_PORT_NET_DEFAULT; + cfg->rtp_processing_cb = &mgcp_rtp_processing_default; + cfg->setup_rtp_processing_cb = &mgcp_setup_rtp_processing_default; + /* default trunk handling */ cfg->trunk.cfg = cfg; cfg->trunk.trunk_nr = 0; @@ -1234,6 +1243,8 @@ static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end) end->local_alloc = -1; talloc_free(end->fmtp_extra); end->fmtp_extra = NULL; + talloc_free(end->rtp_process_data); + end->rtp_process_data = NULL; /* Set default values */ end->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM; @@ -1388,6 +1399,27 @@ int mgcp_send_reset_ep(struct mgcp_endpoint *endp, int endpoint) return send_agent(endp->cfg, buf, len); } +static void setup_rtp_processing(struct mgcp_endpoint *endp) +{ + struct mgcp_config *cfg = endp->cfg; + + if (endp->type != MGCP_RTP_DEFAULT) + return; + + if (endp->conn_mode == MGCP_CONN_LOOPBACK) + return; + + if (endp->conn_mode & MGCP_CONN_SEND_ONLY) + cfg->setup_rtp_processing_cb(endp, &endp->net_end, &endp->bts_end); + else + cfg->setup_rtp_processing_cb(endp, &endp->net_end, NULL); + + if (endp->conn_mode & MGCP_CONN_RECV_ONLY) + cfg->setup_rtp_processing_cb(endp, &endp->bts_end, &endp->net_end); + else + cfg->setup_rtp_processing_cb(endp, &endp->bts_end, NULL); +} + static void create_transcoder(struct mgcp_endpoint *endp) { int port; -- 1.7.9.5 From jerlbeck at sysmocom.de Mon May 12 10:38:58 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Mon, 12 May 2014 12:38:58 +0200 Subject: [PATCH 02/11] mgcp: Add audio info fields to struct mgcp_rtp_end In-Reply-To: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1399891147-31419-2-git-send-email-jerlbeck@sysmocom.de> This patch adds the fields channels, subtype_name, and audio_name to the struct. The field audio_name contains the full string that has been used for the last part of a SDP a=rtpmap line. The others contain decoded parts of that string. If no a=rtpmap line has been given (e.g. because dynamic payload types are not used), values are assigned when the payload type matches one of the predefined ones (GSM, G729, PCMA). Sponsored-by: On-Waves ehf --- openbsc/include/openbsc/mgcp_internal.h | 3 ++ openbsc/src/libmgcp/mgcp_protocol.c | 82 +++++++++++++++++++++++-------- 2 files changed, 64 insertions(+), 21 deletions(-) diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h index 56c280d..72ac8e9 100644 --- a/openbsc/include/openbsc/mgcp_internal.h +++ b/openbsc/include/openbsc/mgcp_internal.h @@ -81,11 +81,14 @@ struct mgcp_rtp_end { /* per endpoint data */ int payload_type; uint32_t rate; + int channels; uint32_t frame_duration_num; uint32_t frame_duration_den; int frames_per_packet; uint32_t packet_duration_ms; char *fmtp_extra; + char *audio_name; + char *subtype_name; int output_enabled; /* RTP patching */ diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c index 0f8614c..761a35c 100644 --- a/openbsc/src/libmgcp/mgcp_protocol.c +++ b/openbsc/src/libmgcp/mgcp_protocol.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -77,6 +78,7 @@ char *strline_r(char *str, char **saveptr) #define DEFAULT_RTP_AUDIO_FRAME_DUR_DEN 1000 #define DEFAULT_RTP_AUDIO_PACKET_DURATION_MS 20 #define DEFAULT_RTP_AUDIO_DEFAULT_RATE 8000 +#define DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS 1 static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end); @@ -231,6 +233,8 @@ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp, { const char *addr = endp->cfg->local_ip; const char *fmtp_extra = endp->bts_end.fmtp_extra; + const char *audio_name = endp->bts_end.audio_name; + int payload_type = endp->bts_end.payload_type; char sdp_record[4096]; int len; @@ -244,11 +248,12 @@ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp, "c=IN IP4 %s\r\n" "t=0 0\r\n" "m=audio %d RTP/AVP %d\r\n" - "a=rtpmap:%d %s\r\n" + "a=rtpmap:%d%s%s\r\n" "%s%s", endp->ci, endp->ci, addr, addr, - endp->net_end.local_port, endp->bts_end.payload_type, - endp->bts_end.payload_type, endp->tcfg->audio_name, + endp->net_end.local_port, payload_type, + payload_type, + audio_name ? " " : "", audio_name ? audio_name : "", fmtp_extra ? fmtp_extra : "", fmtp_extra ? "\r\n" : ""); if (len < 0 || len >= sizeof(sdp_record)) @@ -514,6 +519,47 @@ static int parse_conn_mode(const char *msg, struct mgcp_endpoint *endp) return ret; } +static int set_audio_info(struct mgcp_rtp_end *rtp, + int payload_type, const char *audio_name) +{ + int rate = 8000; + int channels = 1; + char audio_codec[64]; + + talloc_free(rtp->subtype_name); + rtp->subtype_name = NULL; + talloc_free(rtp->audio_name); + rtp->audio_name = NULL; + + rtp->payload_type = payload_type; + + if (!audio_name) { + switch (payload_type) { + case 3: audio_name = "GSM/8000/1"; break; + case 8: audio_name = "PCMA/8000/1"; break; + case 18: audio_name = "G729/8000/1"; break; + default: + rtp->rate = 8000; + rtp->channels = 1; + return 0; + } + } + + if (sscanf(audio_name, "%63[^/]/%d/%d", + audio_codec, &rate, &channels) < 2) + return -EINVAL; + + rtp->rate = rate; + rtp->channels = channels; + rtp->subtype_name = talloc_strdup(NULL, audio_codec); + rtp->audio_name = talloc_strdup(NULL, audio_name); + if (channels != 1) + LOGP(DMGCP, LOGL_NOTICE, + "Channels != 1 in SDP: '%s'\n", audio_name); + + return 0; +} + static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_rtp_end *end, struct mgcp_port_range *range, int (*alloc)(struct mgcp_endpoint *endp, int port)) @@ -600,29 +646,18 @@ static int parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p) break; case 'a': { int payload; - int rate; - int channels = 1; int ptime, ptime2 = 0; char audio_name[64]; - char audio_codec[64]; if (audio_payload == -1) break; - if (sscanf(line, "a=rtpmap:%d %64s", + if (sscanf(line, "a=rtpmap:%d %63s", &payload, audio_name) == 2) { if (payload != audio_payload) break; - if (sscanf(audio_name, "%[^/]/%d/%d", - audio_codec, &rate, &channels) < 2) - break; - - rtp->rate = rate; - if (channels != 1) - LOGP(DMGCP, LOGL_NOTICE, - "Channels != 1 in SDP: '%s' on 0x%x\n", - line, ENDPOINT_NUMBER(p->endp)); + set_audio_info(rtp, payload, audio_name); } else if (sscanf(line, "a=ptime:%d-%d", &ptime, &ptime2) >= 1) { if (ptime2 > 0 && ptime2 != ptime) @@ -645,8 +680,8 @@ static int parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p) &port, &audio_payload) == 2) { rtp->rtp_port = htons(port); rtp->rtcp_port = htons(port + 1); - rtp->payload_type = audio_payload; found_media = 1; + set_audio_info(rtp, audio_payload, NULL); } break; } @@ -826,7 +861,7 @@ mgcp_header_done: endp->allocated = 1; /* set up RTP media parameters */ - endp->bts_end.payload_type = tcfg->audio_payload; + set_audio_info(&endp->bts_end, tcfg->audio_payload, tcfg->audio_name); endp->bts_end.fmtp_extra = talloc_strdup(tcfg->endpoints, tcfg->audio_fmtp_extra); if (have_sdp) { @@ -1252,6 +1287,7 @@ static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end) end->frames_per_packet = 0; /* unknown */ end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS; end->rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE; + end->channels = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS; end->output_enabled = 0; } @@ -1329,6 +1365,9 @@ static void send_msg(struct mgcp_endpoint *endp, int endpoint, int port, { char buf[2096]; int len; + const char *fmtp_extra = endp->bts_end.fmtp_extra; + const char *audio_name = endp->bts_end.audio_name; + int payload_type = endp->bts_end.payload_type; /* hardcoded to AMR right now, we do not know the real type at this point */ len = snprintf(buf, sizeof(buf), @@ -1338,10 +1377,11 @@ static void send_msg(struct mgcp_endpoint *endp, int endpoint, int port, "\r\n" "c=IN IP4 %s\r\n" "m=audio %d RTP/AVP %d\r\n" - "a=rtpmap:%d %s\r\n", + "a=rtpmap:%d%s%s\r\n", msg, endpoint, mode, endp->cfg->source_addr, - port, endp->tcfg->audio_payload, - endp->tcfg->audio_payload, endp->tcfg->audio_name); + port, payload_type, + payload_type, + audio_name ? " " : "", audio_name ? audio_name : ""); if (len < 0) return; -- 1.7.9.5 From holger at freyther.de Wed May 14 05:31:51 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Wed, 14 May 2014 07:31:51 +0200 Subject: [PATCH 02/11] mgcp: Add audio info fields to struct mgcp_rtp_end In-Reply-To: <1399891147-31419-2-git-send-email-jerlbeck@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> <1399891147-31419-2-git-send-email-jerlbeck@sysmocom.de> Message-ID: <20140514053151.GG26057@xiaoyu.lan> On Mon, May 12, 2014 at 12:38:58PM +0200, Jacob Erlbeck wrote: > + rtp->subtype_name = talloc_strdup(NULL, audio_codec); > + rtp->audio_name = talloc_strdup(NULL, audio_name); Attach this to a context that at least belongs to a MGCP context. Make sure to release these strings in mgcp_free_endp or in the reset one. Or did I miss a call to set_audio_info? From jerlbeck at sysmocom.de Mon May 12 10:38:59 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Mon, 12 May 2014 12:38:59 +0200 Subject: [PATCH 03/11] mgcp: Add a function to get media info for MGCP responses In-Reply-To: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1399891147-31419-3-git-send-email-jerlbeck@sysmocom.de> This patch adds the get_net_downlink_format_cb() callback to provide payload_type, subtype_name, and fmtp_extra suitable for use in a MGCP response sent to the network. Per default, the BTS side values are returned since these must be honoured by the net peer when sending audio to the media gateway (unless transcoding is done). Sponsored-by: On-Waves ehf --- openbsc/include/openbsc/mgcp.h | 8 ++++++++ openbsc/include/openbsc/mgcp_internal.h | 5 +++++ openbsc/src/libmgcp/mgcp_network.c | 13 +++++++++++++ openbsc/src/libmgcp/mgcp_protocol.c | 20 ++++++++++++++------ 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h index 6ba0769..b595aba 100644 --- a/openbsc/include/openbsc/mgcp.h +++ b/openbsc/include/openbsc/mgcp.h @@ -92,6 +92,12 @@ typedef int (*mgcp_processing)(struct mgcp_rtp_end *dst_end, typedef int (*mgcp_processing_setup)(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end, struct mgcp_rtp_end *src_end); + +typedef void (*mgcp_get_format)(struct mgcp_endpoint *endp, + int *payload_type, + const char**subtype_name, + const char**fmtp_extra); + #define PORT_ALLOC_STATIC 0 #define PORT_ALLOC_DYNAMIC 1 @@ -166,6 +172,8 @@ struct mgcp_config { mgcp_processing rtp_processing_cb; mgcp_processing_setup setup_rtp_processing_cb; + mgcp_get_format get_net_downlink_format_cb; + struct osmo_wqueue gw_fd; struct mgcp_port_range bts_ports; diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h index 72ac8e9..e74b9fa 100644 --- a/openbsc/include/openbsc/mgcp_internal.h +++ b/openbsc/include/openbsc/mgcp_internal.h @@ -209,4 +209,9 @@ int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end, struct mgcp_rtp_end *src_end); +void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp, + int *payload_type, + const char**subtype_name, + const char**fmtp_extra); + #endif diff --git a/openbsc/src/libmgcp/mgcp_network.c b/openbsc/src/libmgcp/mgcp_network.c index 4d1ad35..dcbb97a 100644 --- a/openbsc/src/libmgcp/mgcp_network.c +++ b/openbsc/src/libmgcp/mgcp_network.c @@ -361,6 +361,19 @@ int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp, return 0; } +void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp, + int *payload_type, + const char**audio_name, + const char**fmtp_extra) +{ + /* Use the BTS side parameters when passing the SDP data (for + * downlink) to the net peer. + */ + *payload_type = endp->bts_end.payload_type; + *audio_name = endp->bts_end.audio_name; + *fmtp_extra = endp->bts_end.fmtp_extra; +} + /** * The RFC 3550 Appendix A assumes there are multiple sources but * some of the supported endpoints (e.g. the nanoBTS) can only handle diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c index 761a35c..b23a56a 100644 --- a/openbsc/src/libmgcp/mgcp_protocol.c +++ b/openbsc/src/libmgcp/mgcp_protocol.c @@ -232,12 +232,15 @@ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp, const char *msg, const char *trans_id) { const char *addr = endp->cfg->local_ip; - const char *fmtp_extra = endp->bts_end.fmtp_extra; - const char *audio_name = endp->bts_end.audio_name; - int payload_type = endp->bts_end.payload_type; + const char *fmtp_extra; + const char *audio_name; + int payload_type; char sdp_record[4096]; int len; + endp->cfg->get_net_downlink_format_cb(endp, &payload_type, + &audio_name, &fmtp_extra); + if (!addr) addr = endp->cfg->source_addr; @@ -1213,6 +1216,8 @@ struct mgcp_config *mgcp_config_alloc(void) cfg->rtp_processing_cb = &mgcp_rtp_processing_default; cfg->setup_rtp_processing_cb = &mgcp_setup_rtp_processing_default; + cfg->get_net_downlink_format_cb = &mgcp_get_net_downlink_format_default; + /* default trunk handling */ cfg->trunk.cfg = cfg; cfg->trunk.trunk_nr = 0; @@ -1365,9 +1370,12 @@ static void send_msg(struct mgcp_endpoint *endp, int endpoint, int port, { char buf[2096]; int len; - const char *fmtp_extra = endp->bts_end.fmtp_extra; - const char *audio_name = endp->bts_end.audio_name; - int payload_type = endp->bts_end.payload_type; + const char *fmtp_extra; + const char *audio_name; + int payload_type; + + endp->cfg->get_net_downlink_format_cb(endp, &payload_type, + &audio_name, &fmtp_extra); /* hardcoded to AMR right now, we do not know the real type at this point */ len = snprintf(buf, sizeof(buf), -- 1.7.9.5 From jerlbeck at sysmocom.de Mon May 12 10:39:00 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Mon, 12 May 2014 12:39:00 +0200 Subject: [PATCH 04/11] mgcp: Only include SDP lines with valid content In-Reply-To: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1399891147-31419-4-git-send-email-jerlbeck@sysmocom.de> Don't show media related lines if the payload type has not been set. Don't show a 'a=rtpmap' line if the audio_name has not been set. This patch unifies the SDP generation of create_response_with_sdp() and send_msg(). Sponsored-by: On-Waves ehf --- openbsc/src/libmgcp/mgcp_protocol.c | 129 +++++++++++++++++++++++------------ 1 file changed, 87 insertions(+), 42 deletions(-) diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c index b23a56a..62bf481 100644 --- a/openbsc/src/libmgcp/mgcp_protocol.c +++ b/openbsc/src/libmgcp/mgcp_protocol.c @@ -228,55 +228,103 @@ static struct msgb *create_err_response(struct mgcp_endpoint *endp, return create_resp(endp, code, " FAIL", msg, trans, NULL, NULL); } -static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp, - const char *msg, const char *trans_id) +static int write_response_sdp(struct mgcp_endpoint *endp, + char *sdp_record, size_t size, const char *addr) { - const char *addr = endp->cfg->local_ip; const char *fmtp_extra; const char *audio_name; int payload_type; - char sdp_record[4096]; int len; + int nchars; endp->cfg->get_net_downlink_format_cb(endp, &payload_type, &audio_name, &fmtp_extra); - if (!addr) - addr = endp->cfg->source_addr; - - len = snprintf(sdp_record, sizeof(sdp_record) - 1, - "I: %u\n\n" + len = snprintf(sdp_record, size, "v=0\r\n" "o=- %u 23 IN IP4 %s\r\n" "c=IN IP4 %s\r\n" - "t=0 0\r\n" - "m=audio %d RTP/AVP %d\r\n" - "a=rtpmap:%d%s%s\r\n" - "%s%s", - endp->ci, endp->ci, addr, addr, - endp->net_end.local_port, payload_type, - payload_type, - audio_name ? " " : "", audio_name ? audio_name : "", - fmtp_extra ? fmtp_extra : "", fmtp_extra ? "\r\n" : ""); - - if (len < 0 || len >= sizeof(sdp_record)) + "t=0 0\r\n", + endp->ci, addr, addr); + + if (len < 0 || len >= size) goto buffer_too_small; + if (payload_type >= 0) { + nchars = snprintf(sdp_record + len, size - len, + "m=audio %d RTP/AVP %d\r\n", + endp->net_end.local_port, payload_type); + if (nchars < 0 || nchars >= size - len) + goto buffer_too_small; + + len += nchars; + + if (audio_name) { + nchars = snprintf(sdp_record + len, size - len, + "a=rtpmap:%d %s\r\n", + payload_type, audio_name); + + if (nchars < 0 || nchars >= size - len) + goto buffer_too_small; + + len += nchars; + } + + if (fmtp_extra) { + nchars = snprintf(sdp_record + len, size - len, + "a=rtpmap:%d %s\r\n", + payload_type, audio_name); + + if (nchars < 0 || nchars >= size - len) + goto buffer_too_small; + + len += nchars; + } + } if (endp->bts_end.packet_duration_ms > 0 && endp->tcfg->audio_send_ptime) { - int nchars = snprintf(sdp_record + len, sizeof(sdp_record) - len, - "a=ptime:%d\r\n", - endp->bts_end.packet_duration_ms); - if (nchars < 0 || nchars >= sizeof(sdp_record) - len) + nchars = snprintf(sdp_record + len, size - len, + "a=ptime:%d\r\n", + endp->bts_end.packet_duration_ms); + if (nchars < 0 || nchars >= size - len) goto buffer_too_small; len += nchars; } - return create_resp(endp, 200, " OK", msg, trans_id, NULL, sdp_record); + + return len; buffer_too_small: LOGP(DMGCP, LOGL_ERROR, "SDP buffer too small: %d (needed %d)\n", - sizeof(sdp_record), len); - return NULL; + size, len); + return -1; +} + +static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp, + const char *msg, const char *trans_id) +{ + const char *addr = endp->cfg->local_ip; + char sdp_record[4096]; + int len; + int nchars; + + if (!addr) + addr = endp->cfg->source_addr; + + len = snprintf(sdp_record, sizeof(sdp_record), "I: %u\n\n", endp->ci); + + if (len < 0) + return NULL; + + nchars = write_response_sdp(endp, sdp_record + len, + sizeof(sdp_record) - len - 1, addr); + if (nchars < 0) + return NULL; + + len += nchars; + + sdp_record[sizeof(sdp_record) - 1] = '\0'; + + return create_resp(endp, 200, " OK", msg, trans_id, NULL, sdp_record); } /* @@ -711,9 +759,10 @@ static int parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p) if (found_media) LOGP(DMGCP, LOGL_NOTICE, - "Got media info via SDP: port %d, payload %d, " + "Got media info via SDP: port %d, payload %d (%s), " "duration %d, addr %s\n", ntohs(rtp->rtp_port), rtp->payload_type, + rtp->subtype_name ? rtp->subtype_name : "unknown", rtp->packet_duration_ms, inet_ntoa(rtp->addr)); return found_media; @@ -1370,30 +1419,26 @@ static void send_msg(struct mgcp_endpoint *endp, int endpoint, int port, { char buf[2096]; int len; - const char *fmtp_extra; - const char *audio_name; - int payload_type; - - endp->cfg->get_net_downlink_format_cb(endp, &payload_type, - &audio_name, &fmtp_extra); + int nchars; /* hardcoded to AMR right now, we do not know the real type at this point */ len = snprintf(buf, sizeof(buf), "%s 42 %x at mgw MGCP 1.0\r\n" "C: 4256\r\n" "M: %s\r\n" - "\r\n" - "c=IN IP4 %s\r\n" - "m=audio %d RTP/AVP %d\r\n" - "a=rtpmap:%d%s%s\r\n", - msg, endpoint, mode, endp->cfg->source_addr, - port, payload_type, - payload_type, - audio_name ? " " : "", audio_name ? audio_name : ""); + "\r\n", + msg, endpoint, mode); if (len < 0) return; + nchars = write_response_sdp(endp, buf + len, sizeof(buf) + len - 1, + endp->cfg->source_addr); + if (nchars < 0) + return; + + len += nchars; + buf[sizeof(buf) - 1] = '\0'; send_trans(endp->cfg, buf, len); -- 1.7.9.5 From holger at freyther.de Wed May 14 05:35:55 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Wed, 14 May 2014 07:35:55 +0200 Subject: [PATCH 04/11] mgcp: Only include SDP lines with valid content In-Reply-To: <1399891147-31419-4-git-send-email-jerlbeck@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> <1399891147-31419-4-git-send-email-jerlbeck@sysmocom.de> Message-ID: <20140514053555.GH26057@xiaoyu.lan> On Mon, May 12, 2014 at 12:39:00PM +0200, Jacob Erlbeck wrote: > Don't show media related lines if the payload type has not been set. > Don't show a 'a=rtpmap' line if the audio_name has not been set. Is creating a regression easy here? Specially for the missing a=rtpmap line? From jerlbeck at sysmocom.de Mon May 12 10:39:01 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Mon, 12 May 2014 12:39:01 +0200 Subject: [PATCH 05/11] mgcp: Add RTP audio transcoding In-Reply-To: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1399891147-31419-5-git-send-email-jerlbeck@sysmocom.de> This patch implements audio transcoding between the formats GSM, PCMA, L16, and optionally G.729. The feature needs to be enabled by using the autoconf option '--enable-mgcp-transcoding'. In this case mgcp_transcode.c will be compiled and linked to osmo-bsc_mgcp, and the transcoding functions provided will be registered as processing callbacks. If G.729 support is required, libcg729 needs to be installed and '--with-g729' must be passed to ./configure. Ticket: OW#1111 Sponsored-by: On-Waves ehf --- openbsc/configure.ac | 15 + openbsc/src/osmo-bsc_mgcp/Makefile.am | 10 +- openbsc/src/osmo-bsc_mgcp/g711common.h | 187 ++++++++++++ openbsc/src/osmo-bsc_mgcp/mgcp_main.c | 15 + openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c | 459 ++++++++++++++++++++++++++++ openbsc/src/osmo-bsc_mgcp/mgcp_transcode.h | 34 +++ 6 files changed, 718 insertions(+), 2 deletions(-) create mode 100644 openbsc/src/osmo-bsc_mgcp/g711common.h create mode 100644 openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c create mode 100644 openbsc/src/osmo-bsc_mgcp/mgcp_transcode.h diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 978f526..ead05af 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -56,6 +56,21 @@ fi AM_CONDITIONAL(BUILD_SMPP, test "x$osmo_ac_build_smpp" = "xyes") AC_SUBST(osmo_ac_build_smpp) +# Enable/disable transcoding within osmo-bsc_mgcp? +AC_ARG_ENABLE([mgcp-transcoding], [AS_HELP_STRING([--enable-mgcp-transcoding], [Build the MGCP gateway with internal transcoding enabled.])], + [osmo_ac_mgcp_transcoding="$enableval"],[osmo_ac_mgcp_transcoding="no"]) +AC_ARG_WITH([g729], [AS_HELP_STRING([--with-g729], [Enable G.729 encoding/decoding.])], [osmo_ac_with_g729="$withval"],[osmo_ac_with_g729="no"]) + +if test "$osmo_ac_mgcp_transcoding" = "yes" ; then + AC_SEARCH_LIBS(gsm_create, gsm) + if test "$osmo_ac_with_g729" = "yes" ; then + PKG_CHECK_MODULES(LIBBCG729, libbcg729 >= 0.1, [AC_DEFINE([HAVE_BCG729], [1], [Use bgc729 decoder/encoder])]) + fi + AC_DEFINE(BUILD_MGCP_TRANSCODING, 1, [Define if we want to build the MGCP gateway with transcoding support]) +fi +AM_CONDITIONAL(BUILD_MGCP_TRANSCODING, test "x$osmo_ac_mgcp_transcoding" = "xyes") +AC_SUBST(osmo_ac_mgcp_transcoding) + found_libgtp=yes PKG_CHECK_MODULES(LIBGTP, libgtp, , found_libgtp=no) diff --git a/openbsc/src/osmo-bsc_mgcp/Makefile.am b/openbsc/src/osmo-bsc_mgcp/Makefile.am index 0456cf1..a620e7a 100644 --- a/openbsc/src/osmo-bsc_mgcp/Makefile.am +++ b/openbsc/src/osmo-bsc_mgcp/Makefile.am @@ -1,10 +1,16 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) \ - $(LIBOSMOVTY_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) + $(LIBOSMOVTY_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) \ + $(LIBBCG729_CFLAGS) bin_PROGRAMS = osmo-bsc_mgcp osmo_bsc_mgcp_SOURCES = mgcp_main.c +if BUILD_MGCP_TRANSCODING + osmo_bsc_mgcp_SOURCES += mgcp_transcode.c +endif osmo_bsc_mgcp_LDADD = $(top_builddir)/src/libcommon/libcommon.a \ $(top_builddir)/src/libmgcp/libmgcp.a -lrt \ - $(LIBOSMOVTY_LIBS) $(LIBOSMOCORE_LIBS) + $(LIBOSMOVTY_LIBS) $(LIBOSMOCORE_LIBS) $(LIBBCG729_LIBS) + +noinst_HEADERS = g711common.h mgcp_transcode.h diff --git a/openbsc/src/osmo-bsc_mgcp/g711common.h b/openbsc/src/osmo-bsc_mgcp/g711common.h new file mode 100644 index 0000000..cb35fc6 --- /dev/null +++ b/openbsc/src/osmo-bsc_mgcp/g711common.h @@ -0,0 +1,187 @@ +/* + * PCM - A-Law conversion + * Copyright (c) 2000 by Abramo Bagnara + * + * Wrapper for linphone Codec class by Simon Morlat + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +static inline int val_seg(int val) +{ + int r = 0; + val >>= 7; /*7 = 4 + 3*/ + if (val & 0xf0) { + val >>= 4; + r += 4; + } + if (val & 0x0c) { + val >>= 2; + r += 2; + } + if (val & 0x02) + r += 1; + return r; +} + +/* + * s16_to_alaw() - Convert a 16-bit linear PCM value to 8-bit A-law + * + * s16_to_alaw() accepts an 16-bit integer and encodes it as A-law data. + * + * Linear Input Code Compressed Code + * ------------------------ --------------- + * 0000000wxyza 000wxyz + * 0000001wxyza 001wxyz + * 000001wxyzab 010wxyz + * 00001wxyzabc 011wxyz + * 0001wxyzabcd 100wxyz + * 001wxyzabcde 101wxyz + * 01wxyzabcdef 110wxyz + * 1wxyzabcdefg 111wxyz + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + * G711 is designed for 13 bits input signal, this function add extra shifting to take this into account. + */ + +static inline unsigned char s16_to_alaw(int pcm_val) +{ + int mask; + int seg; + unsigned char aval; + + if (pcm_val >= 0) { + mask = 0xD5; + } else { + mask = 0x55; + pcm_val = -pcm_val; + if (pcm_val > 0x7fff) + pcm_val = 0x7fff; + } + + if (pcm_val < 256) /*256 = 32 << 3*/ + aval = pcm_val >> 4; /*4 = 1 + 3*/ + else { + /* Convert the scaled magnitude to segment number. */ + seg = val_seg(pcm_val); + aval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f); + } + return aval ^ mask; +} + +/* + * alaw_to_s16() - Convert an A-law value to 16-bit linear PCM + * + */ +static inline int alaw_to_s16(unsigned char a_val) +{ + int t; + int seg; + + a_val ^= 0x55; + t = a_val & 0x7f; + if (t < 16) + t = (t << 4) + 8; + else { + seg = (t >> 4) & 0x07; + t = ((t & 0x0f) << 4) + 0x108; + t <<= seg -1; + } + return ((a_val & 0x80) ? t : -t); +} +/* + * s16_to_ulaw() - Convert a linear PCM value to u-law + * + * In order to simplify the encoding process, the original linear magnitude + * is biased by adding 33 which shifts the encoding range from (0 - 8158) to + * (33 - 8191). The result can be seen in the following encoding table: + * + * Biased Linear Input Code Compressed Code + * ------------------------ --------------- + * 00000001wxyza 000wxyz + * 0000001wxyzab 001wxyz + * 000001wxyzabc 010wxyz + * 00001wxyzabcd 011wxyz + * 0001wxyzabcde 100wxyz + * 001wxyzabcdef 101wxyz + * 01wxyzabcdefg 110wxyz + * 1wxyzabcdefgh 111wxyz + * + * Each biased linear code has a leading 1 which identifies the segment + * number. The value of the segment number is equal to 7 minus the number + * of leading 0's. The quantization interval is directly available as the + * four bits wxyz. * The trailing bits (a - h) are ignored. + * + * Ordinarily the complement of the resulting code word is used for + * transmission, and so the code word is complemented before it is returned. + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ + +static inline unsigned char s16_to_ulaw(int pcm_val) /* 2's complement (16-bit range) */ +{ + int mask; + int seg; + unsigned char uval; + + if (pcm_val < 0) { + pcm_val = 0x84 - pcm_val; + mask = 0x7f; + } else { + pcm_val += 0x84; + mask = 0xff; + } + if (pcm_val > 0x7fff) + pcm_val = 0x7fff; + + /* Convert the scaled magnitude to segment number. */ + seg = val_seg(pcm_val); + + /* + * Combine the sign, segment, quantization bits; + * and complement the code word. + */ + uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f); + return uval ^ mask; +} + +/* + * ulaw_to_s16() - Convert a u-law value to 16-bit linear PCM + * + * First, a biased linear code is derived from the code word. An unbiased + * output can then be obtained by subtracting 33 from the biased code. + * + * Note that this function expects to be passed the complement of the + * original code word. This is in keeping with ISDN conventions. + */ +static inline int ulaw_to_s16(unsigned char u_val) +{ + int t; + + /* Complement to obtain normal u-law value. */ + u_val = ~u_val; + + /* + * Extract and bias the quantization bits. Then + * shift up by the segment number and subtract out the bias. + */ + t = ((u_val & 0x0f) << 3) + 0x84; + t <<= (u_val & 0x70) >> 4; + + return ((u_val & 0x80) ? (0x84 - t) : (t - 0x84)); +} diff --git a/openbsc/src/osmo-bsc_mgcp/mgcp_main.c b/openbsc/src/osmo-bsc_mgcp/mgcp_main.c index 14ec221..5ac4c26 100644 --- a/openbsc/src/osmo-bsc_mgcp/mgcp_main.c +++ b/openbsc/src/osmo-bsc_mgcp/mgcp_main.c @@ -31,6 +31,11 @@ #include +#include "g711common.h" +#include +#include +#include + #include #include #include @@ -49,6 +54,10 @@ #include "../../bscconfig.h" +#ifdef BUILD_MGCP_TRANSCODING +#include "mgcp_transcode.h" +#endif + /* this is here for the vty... it will never be called */ void subscr_put() { abort(); } @@ -207,6 +216,12 @@ int main(int argc, char **argv) if (!cfg) return -1; +#ifdef BUILD_MGCP_TRANSCODING + cfg->setup_rtp_processing_cb = &mgcp_transcoding_setup; + cfg->rtp_processing_cb = &mgcp_transcoding_process_rtp; + cfg->get_net_downlink_format_cb = &mgcp_transcoding_net_downlink_format; +#endif + vty_info.copyright = openbsc_copyright; vty_init(&vty_info); logging_vty_add_cmds(&log_info); diff --git a/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c b/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c new file mode 100644 index 0000000..c6b2508 --- /dev/null +++ b/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c @@ -0,0 +1,459 @@ +/* + * (C) 2014 by On-Waves + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include + + +#include "../../bscconfig.h" + +#include "g711common.h" +#include +#ifdef HAVE_BCG729 +#include +#include +#endif + +#include +#include +#include + +#include + +enum audio_format { + AF_INVALID, + AF_S16, + AF_L16, + AF_GSM, + AF_G729, + AF_PCMA +}; + +struct mgcp_process_rtp_state { + /* decoding */ + enum audio_format src_fmt; + union { + gsm gsm_handle; +#ifdef HAVE_BCG729 + bcg729DecoderChannelContextStruct *g729_dec; +#endif + } src; + size_t src_frame_size; + size_t src_samples_per_frame; + + /* processing */ + + /* encoding */ + enum audio_format dst_fmt; + union { + gsm gsm_handle; +#ifdef HAVE_BCG729 + bcg729EncoderChannelContextStruct *g729_enc; +#endif + } dst; + size_t dst_frame_size; + size_t dst_samples_per_frame; +}; + +static enum audio_format get_audio_format(const struct mgcp_rtp_end *rtp_end) +{ + if (rtp_end->subtype_name) { + if (!strcmp("GSM", rtp_end->subtype_name)) + return AF_GSM; + if (!strcmp("PCMA", rtp_end->subtype_name)) + return AF_PCMA; +#ifdef HAVE_BCG729 + if (!strcmp("G729", rtp_end->subtype_name)) + return AF_G729; +#endif + if (!strcmp("L16", rtp_end->subtype_name)) + return AF_L16; + } + + switch (rtp_end->payload_type) { + case 3 /* GSM */: + return AF_GSM; + case 8 /* PCMA */: + return AF_PCMA; +#ifdef HAVE_BCG729 + case 18 /* G.729 */: + return AF_G729; +#endif + case 11 /* L16 */: + return AF_L16; + default: + return AF_INVALID; + } +} + +static void l16_encode(short *sample, unsigned char *buf, size_t n) +{ + for (; n > 0; --n, ++sample, buf += 2) { + buf[0] = sample[0] >> 8; + buf[1] = sample[0] & 0xff; + } +} + +static void l16_decode(unsigned char *buf, short *sample, size_t n) +{ + for (; n > 0; --n, ++sample, buf += 2) + sample[0] = ((short)buf[0] << 8) | buf[1]; +} + +static void alaw_encode(short *sample, unsigned char *buf, size_t n) +{ + for (; n > 0; --n) + *(buf++) = s16_to_alaw(*(sample++)); +} + +static void alaw_decode(unsigned char *buf, short *sample, size_t n) +{ + for (; n > 0; --n) + *(sample++) = alaw_to_s16(*(buf++)); +} + +static int processing_state_destructor(struct mgcp_process_rtp_state *state) +{ + switch (state->src_fmt) { + case AF_GSM: + if (state->dst.gsm_handle) + gsm_destroy(state->src.gsm_handle); + break; +#ifdef HAVE_BCG729 + case AF_G729: + if (state->src.g729_dec) + closeBcg729DecoderChannel(state->src.g729_dec); + break; +#endif + default: + break; + } + switch (state->dst_fmt) { + case AF_GSM: + if (state->dst.gsm_handle) + gsm_destroy(state->dst.gsm_handle); + break; +#ifdef HAVE_BCG729 + case AF_G729: + if (state->dst.g729_enc) + closeBcg729EncoderChannel(state->dst.g729_enc); + break; +#endif + default: + break; + } + return 0; +} + +int mgcp_transcoding_setup(struct mgcp_endpoint *endp, + struct mgcp_rtp_end *dst_end, + struct mgcp_rtp_end *src_end) +{ + struct mgcp_process_rtp_state *state = dst_end->rtp_process_data; + enum audio_format src_fmt, dst_fmt; + + /* cleanup first */ + if (state) { + talloc_free(state); + dst_end->rtp_process_data = NULL; + } + + if (!src_end) + return 0; + + src_fmt = get_audio_format(src_end); + dst_fmt = get_audio_format(dst_end); + + LOGP(DMGCP, LOGL_ERROR, + "Checking transcoding: %s (%d) -> %s (%d)\n", + src_end->subtype_name, src_end->payload_type, + dst_end->subtype_name, dst_end->payload_type); + + if (src_fmt == AF_INVALID || dst_fmt == AF_INVALID) { + if (!src_end->subtype_name || !dst_end->subtype_name) + /* Not enough info, do nothing */ + return 0; + + if (strcmp(src_end->subtype_name, dst_end->subtype_name) == 0) + /* Nothing to do */ + return 0; + + LOGP(DMGCP, LOGL_ERROR, + "Cannot transcode: %s codec not supported (%s -> %s).\n", + src_fmt != AF_INVALID ? "destination" : "source", + src_end->audio_name, dst_end->audio_name); + return -EINVAL; + } + + if (src_end->rate && dst_end->rate && src_end->rate != dst_end->rate) { + LOGP(DMGCP, LOGL_ERROR, + "Cannot transcode: rate conversion (%d -> %d) not supported.\n", + src_end->rate, dst_end->rate); + return -EINVAL; + } + + state = talloc_zero(endp->tcfg->cfg, struct mgcp_process_rtp_state); + talloc_set_destructor(state, processing_state_destructor); + dst_end->rtp_process_data = state; + + state->src_fmt = src_fmt; + + switch (state->src_fmt) { + case AF_L16: + case AF_S16: + state->src_frame_size = 80 * sizeof(short); + state->src_samples_per_frame = 80; + break; + case AF_GSM: + state->src_frame_size = sizeof(gsm_frame); + state->src_samples_per_frame = 160; + state->src.gsm_handle = gsm_create(); + if (!state->src.gsm_handle) { + LOGP(DMGCP, LOGL_ERROR, + "Failed to initialize GSM decoder.\n"); + return -EINVAL; + } + break; +#ifdef HAVE_BCG729 + case AF_G729: + state->src_frame_size = 10; + state->src_samples_per_frame = 80; + state->src.g729_dec = initBcg729DecoderChannel(); + if (!state->src.g729_dec) { + LOGP(DMGCP, LOGL_ERROR, + "Failed to initialize G.729 decoder.\n"); + return -EINVAL; + } + break; +#endif + case AF_PCMA: + state->src_frame_size = 80; + state->src_samples_per_frame = 80; + break; + default: + break; + } + + state->dst_fmt = dst_fmt; + + switch (state->dst_fmt) { + case AF_L16: + case AF_S16: + state->dst_frame_size = 80*sizeof(short); + state->dst_samples_per_frame = 80; + break; + case AF_GSM: + state->dst_frame_size = sizeof(gsm_frame); + state->dst_samples_per_frame = 160; + state->dst.gsm_handle = gsm_create(); + if (!state->dst.gsm_handle) { + LOGP(DMGCP, LOGL_ERROR, + "Failed to initialize GSM encoder.\n"); + return -EINVAL; + } + break; +#ifdef HAVE_BCG729 + case AF_G729: + state->dst_frame_size = 10; + state->dst_samples_per_frame = 80; + state->dst.g729_enc = initBcg729EncoderChannel(); + if (!state->dst.g729_enc) { + LOGP(DMGCP, LOGL_ERROR, + "Failed to initialize G.729 decoder.\n"); + return -EINVAL; + } + break; +#endif + case AF_PCMA: + state->dst_frame_size = 80; + state->dst_samples_per_frame = 80; + break; + default: + break; + } + + LOGP(DMGCP, LOGL_INFO, + "Initialized RTP processing on: 0x%x " + "conv: %d (%d, %d, %s) -> %d (%d, %d, %s)\n", + ENDPOINT_NUMBER(endp), + src_fmt, src_end->payload_type, src_end->rate, src_end->fmtp_extra, + dst_fmt, dst_end->payload_type, dst_end->rate, dst_end->fmtp_extra); + + return 0; +} + +void mgcp_transcoding_net_downlink_format(struct mgcp_endpoint *endp, + int *payload_type, + const char**audio_name, + const char**fmtp_extra) +{ + struct mgcp_process_rtp_state *state = endp->net_end.rtp_process_data; + if (!state || endp->net_end.payload_type < 0) { + *payload_type = endp->bts_end.payload_type; + *audio_name = endp->bts_end.audio_name; + *fmtp_extra = endp->bts_end.fmtp_extra; + return; + } + + *payload_type = endp->net_end.payload_type; + *fmtp_extra = endp->net_end.fmtp_extra; + *audio_name = endp->net_end.audio_name; +} + + +int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp, + struct mgcp_rtp_end *dst_end, + char *data, int *len, int buf_size) +{ + struct mgcp_process_rtp_state *state = dst_end->rtp_process_data; + size_t rtp_hdr_size = 12; + char *payload_data = data + rtp_hdr_size; + int payload_len = *len - rtp_hdr_size; + size_t sample_cnt = 0; + size_t sample_idx; + int16_t samples[10*160]; + uint8_t *src = (uint8_t *)payload_data; + uint8_t *dst = (uint8_t *)payload_data; + size_t nbytes = payload_len; + size_t frame_remainder; + + if (!state) + return 0; + + if (state->src_fmt == state->dst_fmt) + return 0; + + /* TODO: check payload type (-> G.711 comfort noise) */ + + /* Decode src into samples */ + while (nbytes >= state->src_frame_size) { + if (sample_cnt + state->src_samples_per_frame > ARRAY_SIZE(samples)) { + LOGP(DMGCP, LOGL_ERROR, + "Sample buffer too small: %d > %d.\n", + sample_cnt + state->src_samples_per_frame, + ARRAY_SIZE(samples)); + return -ENOSPC; + } + switch (state->src_fmt) { + case AF_GSM: + if (gsm_decode(state->src.gsm_handle, + (gsm_byte *)src, samples + sample_cnt) < 0) { + LOGP(DMGCP, LOGL_ERROR, + "Failed to decode GSM.\n"); + return -EINVAL; + } + break; +#ifdef HAVE_BCG729 + case AF_G729: + bcg729Decoder(state->src.g729_dec, src, 0, samples + sample_cnt); + break; +#endif + case AF_PCMA: + alaw_decode(src, samples + sample_cnt, + state->src_samples_per_frame); + break; + case AF_S16: + memmove(samples + sample_cnt, src, + state->src_frame_size); + break; + case AF_L16: + l16_decode(src, samples + sample_cnt, + state->src_samples_per_frame); + break; + default: + break; + } + src += state->src_frame_size; + nbytes -= state->src_frame_size; + sample_cnt += state->src_samples_per_frame; + } + + /* Add silence if necessary */ + frame_remainder = sample_cnt % state->dst_samples_per_frame; + if (frame_remainder) { + size_t silence = state->dst_samples_per_frame - frame_remainder; + if (sample_cnt + silence > ARRAY_SIZE(samples)) { + LOGP(DMGCP, LOGL_ERROR, + "Sample buffer too small for silence: %d > %d.\n", + sample_cnt + silence, + ARRAY_SIZE(samples)); + return -ENOSPC; + } + + while (silence > 0) { + samples[sample_cnt] = 0; + sample_cnt += 1; + silence -= 1; + } + } + + /* Encode samples into dst */ + sample_idx = 0; + nbytes = 0; + while (sample_idx + state->dst_samples_per_frame <= sample_cnt) { + if (nbytes + state->dst_frame_size > buf_size) { + LOGP(DMGCP, LOGL_ERROR, + "Encoding (RTP) buffer too small: %d > %d.\n", + nbytes + state->dst_frame_size, buf_size); + return -ENOSPC; + } + switch (state->dst_fmt) { + case AF_GSM: + gsm_encode(state->dst.gsm_handle, + samples + sample_idx, dst); + break; +#ifdef HAVE_BCG729 + case AF_G729: + bcg729Encoder(state->dst.g729_enc, + samples + sample_idx, dst); + break; +#endif + case AF_PCMA: + alaw_encode(samples + sample_idx, dst, + state->src_samples_per_frame); + break; + case AF_S16: + memmove(dst, samples + sample_idx, state->dst_frame_size); + break; + case AF_L16: + l16_encode(samples + sample_idx, dst, + state->src_samples_per_frame); + break; + default: + break; + } + dst += state->dst_frame_size; + nbytes += state->dst_frame_size; + sample_idx += state->dst_samples_per_frame; + } + + *len = rtp_hdr_size + nbytes; + /* Patch payload type */ + data[1] = (data[1] & 0x80) | (dst_end->payload_type & 0x7f); + + /* TODO: remove me + fprintf(stderr, "sample_cnt = %d, sample_idx = %d, plen = %d -> %d, " + "hdr_size = %d, len = %d, pt = %d\n", + sample_cnt, sample_idx, payload_len, nbytes, rtp_hdr_size, *len, + data[1]); + */ + + return 0; +} diff --git a/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.h b/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.h new file mode 100644 index 0000000..2dfb06a --- /dev/null +++ b/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.h @@ -0,0 +1,34 @@ +/* + * (C) 2014 by On-Waves + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +#ifndef OPENBSC_MGCP_TRANSCODE_H +#define OPENBSC_MGCP_TRANSCODE_H + +int mgcp_transcoding_setup(struct mgcp_endpoint *endp, + struct mgcp_rtp_end *dst_end, + struct mgcp_rtp_end *src_end); + +void mgcp_transcoding_net_downlink_format(struct mgcp_endpoint *endp, + int *payload_type, + const char**audio_name, + const char**fmtp_extra); + +int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp, + struct mgcp_rtp_end *dst_end, + char *data, int *len, int buf_size); +#endif /* OPENBSC_MGCP_TRANSCODE_H */ -- 1.7.9.5 From holger at freyther.de Wed May 14 05:46:57 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Wed, 14 May 2014 07:46:57 +0200 Subject: [PATCH 05/11] mgcp: Add RTP audio transcoding In-Reply-To: <1399891147-31419-5-git-send-email-jerlbeck@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> <1399891147-31419-5-git-send-email-jerlbeck@sysmocom.de> Message-ID: <20140514054657.GI26057@xiaoyu.lan> On Mon, May 12, 2014 at 12:39:01PM +0200, Jacob Erlbeck wrote: > +#include "g711common.h" > +#include > +#include > +#include these must be guarded with the approriate defines. Specially the g729 ones. I think you are lucky as /usr/include/bcg729/encoder.h just exists. :) > +++ b/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c > @@ -0,0 +1,459 @@ > +/* > + * (C) 2014 by On-Waves shared copyright here. :) > +#include "../../bscconfig.h" Does this work with make distcheck? srcdir != builddir? > + /* cleanup first */ > + if (state) { > + talloc_free(state); > + dst_end->rtp_process_data = NULL; state = NULL; > + } Or just avoid assigning state that early? > + LOGP(DMGCP, LOGL_ERROR, > + "Cannot transcode: %s codec not supported (%s -> %s).\n", > + src_fmt != AF_INVALID ? "destination" : "source", > + src_end->audio_name, dst_end->audio_name); > + return -EINVAL; Will the CRCX/MDCX fail in this case? I am a bit too lazy to check this right now. > + /* TODO: remove me > + fprintf(stderr, "sample_cnt = %d, sample_idx = %d, plen = %d -> %d, " > + "hdr_size = %d, len = %d, pt = %d\n", > + sample_cnt, sample_idx, payload_len, nbytes, rtp_hdr_size, *len, > + data[1]); > + */ You want to keep this for now? > +#ifndef OPENBSC_MGCP_TRANSCODE_H > +#define OPENBSC_MGCP_TRANSCODE_H I started to use "#pragma once". It is supported by GCC for a long time and even the Microsoft Compiler handles it correctly. From jerlbeck at sysmocom.de Wed May 14 12:44:26 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Wed, 14 May 2014 14:44:26 +0200 Subject: [PATCH 05/11] mgcp: Add RTP audio transcoding In-Reply-To: <20140514054657.GI26057@xiaoyu.lan> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> <1399891147-31419-5-git-send-email-jerlbeck@sysmocom.de> <20140514054657.GI26057@xiaoyu.lan> Message-ID: <5373652A.8000409@sysmocom.de> Hello Holger, I'm already modifying the patches and planning to send them tomorrow. On 14.05.2014 07:46, Holger Hans Peter Freyther wrote: > On Mon, May 12, 2014 at 12:39:01PM +0200, Jacob Erlbeck wrote: > >> +#include "g711common.h" >> +#include >> +#include >> +#include > > these must be guarded with the approriate defines. Specially the g729 > ones. I think you are lucky as /usr/include/bcg729/encoder.h just > exists. :) Thanks for spotting those, they're just left overs and can be removed completely (the real ones are in mpgc_transcode.c are guarded). > >> +++ b/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c >> @@ -0,0 +1,459 @@ >> +/* >> + * (C) 2014 by On-Waves > > shared copyright here. :) By whom? > >> +#include "../../bscconfig.h" > > Does this work with make distcheck? srcdir != builddir? Apparently yes. This line dates back to 2010 (5a29c7fa895a14112a1ac65e541f4b87ae9dba04) and can be found like that at several other places too. Removing the '../../' works too, but I don't want to change that within this commit. > >> + /* cleanup first */ >> + if (state) { >> + talloc_free(state); >> + dst_end->rtp_process_data = NULL; > > state = NULL; >> + } > > > Or just avoid assigning state that early? This might called multiply during a single call and this way does a full transcoding reset every time including cleaning up and disabling it when called with src_end == NULL. > >> + LOGP(DMGCP, LOGL_ERROR, >> + "Cannot transcode: %s codec not supported (%s -> %s).\n", >> + src_fmt != AF_INVALID ? "destination" : "source", >> + src_end->audio_name, dst_end->audio_name); >> + return -EINVAL; > > Will the CRCX/MDCX fail in this case? I am a bit too lazy to check this > right now. No. It just falls back to passing all packets unmodified. I'd rather like to address this when real negiation is added, but OTOH it wouldn't be much effort to just terminate the connection in this case. > >> + /* TODO: remove me >> + fprintf(stderr, "sample_cnt = %d, sample_idx = %d, plen = %d -> %d, " >> + "hdr_size = %d, len = %d, pt = %d\n", >> + sample_cnt, sample_idx, payload_len, nbytes, rtp_hdr_size, *len, >> + data[1]); >> + */ > > You want to keep this for now? No. > >> +#ifndef OPENBSC_MGCP_TRANSCODE_H >> +#define OPENBSC_MGCP_TRANSCODE_H > > I started to use "#pragma once". It is supported by GCC for a long > time and even the Microsoft Compiler handles it correctly. > Hmm, I just found that in only single file yet. I'm just traditionally reluctant with #pragma'a in general, but if we want to change the style I can change this accordingly. -- - Jacob Erlbeck http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Schivelbeiner Str. 5 * 10439 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte From holger at freyther.de Thu May 15 08:59:06 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Thu, 15 May 2014 10:59:06 +0200 Subject: [PATCH 05/11] mgcp: Add RTP audio transcoding In-Reply-To: <5373652A.8000409@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> <1399891147-31419-5-git-send-email-jerlbeck@sysmocom.de> <20140514054657.GI26057@xiaoyu.lan> <5373652A.8000409@sysmocom.de> Message-ID: <20140515085906.GD26903@xiaoyu.lan> On Wed, May 14, 2014 at 02:44:26PM +0200, Jacob Erlbeck wrote: Hi! > > I started to use "#pragma once". It is supported by GCC for a long > > time and even the Microsoft Compiler handles it correctly. > > > > Hmm, I just found that in only single file yet. I'm just traditionally > reluctant with #pragma'a in general, but if we want to change the style > I can change this accordingly. I started to use "#pragma once" in the osmo-pcu. I highly encourage to use it for new files. From holger at freyther.de Thu May 15 19:31:35 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Thu, 15 May 2014 21:31:35 +0200 Subject: [PATCH 05/11] mgcp: Add RTP audio transcoding In-Reply-To: <5373652A.8000409@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> <1399891147-31419-5-git-send-email-jerlbeck@sysmocom.de> <20140514054657.GI26057@xiaoyu.lan> <5373652A.8000409@sysmocom.de> Message-ID: <20140515193135.GM26903@xiaoyu.lan> On Wed, May 14, 2014 at 02:44:26PM +0200, Jacob Erlbeck wrote: > >> + /* cleanup first */ > >> + if (state) { > >> + talloc_free(state); > >> + dst_end->rtp_process_data = NULL; > > > > state = NULL; > >> + } > > > > > > Or just avoid assigning state that early? > > This might called multiply during a single call and this way does a full > transcoding reset every time including cleaning up and disabling it when > called with src_end == NULL. Yes, my question was maybe use if (dst_end->rtp_process_data) and assign state only after it. What we should avoid is having state be a dangling pointer. From jerlbeck at sysmocom.de Mon May 12 10:39:02 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Mon, 12 May 2014 12:39:02 +0200 Subject: [PATCH 06/11] mgcp: Add CLI tool to test audio conversion In-Reply-To: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1399891147-31419-6-git-send-email-jerlbeck@sysmocom.de> This tool uses mgcp_transcode.c to convert audio data from stdin to stdout. Sponsored-by: On-Waves ehf --- openbsc/contrib/testconv/Makefile | 17 ++++++ openbsc/contrib/testconv/testconv_main.c | 91 ++++++++++++++++++++++++++++ openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c | 13 ++++ openbsc/src/osmo-bsc_mgcp/mgcp_transcode.h | 2 + 4 files changed, 123 insertions(+) create mode 100644 openbsc/contrib/testconv/Makefile create mode 100644 openbsc/contrib/testconv/testconv_main.c diff --git a/openbsc/contrib/testconv/Makefile b/openbsc/contrib/testconv/Makefile new file mode 100644 index 0000000..90adecc --- /dev/null +++ b/openbsc/contrib/testconv/Makefile @@ -0,0 +1,17 @@ + +OBJS = testconv_main.o mgcp_transcode.o + +CC = gcc +CFLAGS = -O0 -ggdb -Wall +LDFLAGS = +CPPFLAGS = -I../.. -I../../include $(shell pkg-config --cflags libosmocore) $(shell pkg-config --cflags libbcg729) +LIBS = ../../src/libmgcp/libmgcp.a ../../src/libcommon/libcommon.a $(shell pkg-config --libs libosmocore) $(shell pkg-config --libs libbcg729) -lgsm -lrt + +testconv: $(OBJS) + $(CC) -o $@ $^ $(LDFLAGS) $(LIBS) + +testconv_main.o: testconv_main.c +mgcp_transcode.o: ../../src/osmo-bsc_mgcp/mgcp_transcode.c + +$(OBJS): + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< diff --git a/openbsc/contrib/testconv/testconv_main.c b/openbsc/contrib/testconv/testconv_main.c new file mode 100644 index 0000000..c2785f2 --- /dev/null +++ b/openbsc/contrib/testconv/testconv_main.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "bscconfig.h" +#ifndef BUILD_MGCP_TRANSCODING +#error "Requires MGCP transcoding enabled (see --enable-mgcp-transcoding)" +#endif + +#include "src/osmo-bsc_mgcp/mgcp_transcode.h" + +static int audio_name_to_type(const char *name) +{ + if (!strcasecmp(name, "gsm")) + return 3; +#ifdef HAVE_BCG729 + else if (!strcasecmp(name, "g729")) + return 18; +#endif + else if (!strcasecmp(name, "pcma")) + return 8; + else if (!strcasecmp(name, "l16")) + return 11; + return -1; +} + +int mgcp_get_trans_frame_size(void *state_, int nsamples, int dst); + +int main(int argc, char **argv) +{ + char buf[4096] = {0}; + int cc, rc; + struct mgcp_rtp_end dst_end = {0}; + struct mgcp_rtp_end src_end = {0}; + struct mgcp_trunk_config tcfg = {{0}}; + struct mgcp_endpoint endp = {0}; + struct mgcp_process_rtp_state *state; + int in_size; + + osmo_init_logging(&log_info); + + tcfg.endpoints = &endp; + tcfg.number_endpoints = 1; + endp.tcfg = &tcfg; + + if (argc <= 2) + errx(1, "Usage: {gsm|g729|pcma|l16} {gsm|g729|pcma|l16}"); + + if ((src_end.payload_type = audio_name_to_type(argv[1])) == -1) + errx(1, "invalid input format '%s'", argv[1]); + if ((dst_end.payload_type = audio_name_to_type(argv[2])) == -1) + errx(1, "invalid output format '%s'", argv[2]); + + rc = mgcp_transcoding_setup(&endp, &dst_end, &src_end); + if (rc < 0) + errx(1, "setup failed: %s", strerror(-rc)); + + state = dst_end.rtp_process_data; + OSMO_ASSERT(state != NULL); + + in_size = mgcp_transcoding_get_frame_size(state, 160, 0); + OSMO_ASSERT(sizeof(buf) >= in_size + 12); + + while ((cc = read(0, buf + 12, in_size))) { + if (cc != in_size) + err(1, "read"); + + cc += 12; /* include RTP header */ + + rc = mgcp_transcoding_process_rtp(&endp, &dst_end, + buf, &cc, sizeof(buf)); + if (rc < 0) + errx(1, "processing failed: %s", strerror(-rc)); + + cc -= 12; /* ignore RTP header */ + if (write(1, buf + 12, cc) != cc) + err(1, "write"); + } + return 0; +} + diff --git a/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c b/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c index c6b2508..ea4bd74 100644 --- a/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c +++ b/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c @@ -72,6 +72,19 @@ struct mgcp_process_rtp_state { size_t dst_samples_per_frame; }; +int mgcp_transcoding_get_frame_size(void *state_, int nsamples, int dst) +{ + struct mgcp_process_rtp_state *state = state_; + if (dst) + return (nsamples >= 0 ? + nsamples / state->dst_samples_per_frame : + 1) * state->dst_frame_size; + else + return (nsamples >= 0 ? + nsamples / state->src_samples_per_frame : + 1) * state->src_frame_size; +} + static enum audio_format get_audio_format(const struct mgcp_rtp_end *rtp_end) { if (rtp_end->subtype_name) { diff --git a/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.h b/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.h index 2dfb06a..0961634 100644 --- a/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.h +++ b/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.h @@ -31,4 +31,6 @@ void mgcp_transcoding_net_downlink_format(struct mgcp_endpoint *endp, int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end, char *data, int *len, int buf_size); + +int mgcp_transcoding_get_frame_size(void *state_, int nsamples, int dst); #endif /* OPENBSC_MGCP_TRANSCODE_H */ -- 1.7.9.5 From jerlbeck at sysmocom.de Mon May 12 10:39:03 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Mon, 12 May 2014 12:39:03 +0200 Subject: [PATCH 07/11] mgcp: Add packet size (ptime) conversion In-Reply-To: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1399891147-31419-7-git-send-email-jerlbeck@sysmocom.de> The current transcoder implemenation always does a 1:1 recoding concerning the duration of a packet. So RTP timestamps and sequence numbers are not modified. This is not sufficient in some cases, e.g. when the BTS does only allow for a single fixed ptime. This patch decouples encoding from decoding and moves the decoded samples to the state structure so that samples can be combined or drain according to the packaging of incoming and outgoing packets. This patch incorporates parts of Holger's experimental fixes in 0e669e05^..9eba68f9. Ticket: OW#1111 Sponsored-by: On-Waves ehf --- openbsc/contrib/testconv/testconv_main.c | 52 +++++-- openbsc/include/openbsc/mgcp.h | 5 +- openbsc/include/openbsc/mgcp_internal.h | 3 +- openbsc/src/libmgcp/mgcp_network.c | 30 +++- openbsc/src/libmgcp/mgcp_protocol.c | 15 +- openbsc/src/libmgcp/mgcp_vty.c | 22 +++ openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c | 233 +++++++++++++++++++--------- 7 files changed, 259 insertions(+), 101 deletions(-) diff --git a/openbsc/contrib/testconv/testconv_main.c b/openbsc/contrib/testconv/testconv_main.c index c2785f2..aee7304 100644 --- a/openbsc/contrib/testconv/testconv_main.c +++ b/openbsc/contrib/testconv/testconv_main.c @@ -38,10 +38,10 @@ int mgcp_get_trans_frame_size(void *state_, int nsamples, int dst); int main(int argc, char **argv) { - char buf[4096] = {0}; + char buf[4096] = {0x80, 0}; int cc, rc; - struct mgcp_rtp_end dst_end = {0}; - struct mgcp_rtp_end src_end = {0}; + struct mgcp_rtp_end *dst_end; + struct mgcp_rtp_end *src_end; struct mgcp_trunk_config tcfg = {{0}}; struct mgcp_endpoint endp = {0}; struct mgcp_process_rtp_state *state; @@ -52,39 +52,63 @@ int main(int argc, char **argv) tcfg.endpoints = &endp; tcfg.number_endpoints = 1; endp.tcfg = &tcfg; + mgcp_free_endp(&endp); + + dst_end = &endp.bts_end; + src_end = &endp.net_end; if (argc <= 2) errx(1, "Usage: {gsm|g729|pcma|l16} {gsm|g729|pcma|l16}"); - if ((src_end.payload_type = audio_name_to_type(argv[1])) == -1) + if ((src_end->payload_type = audio_name_to_type(argv[1])) == -1) errx(1, "invalid input format '%s'", argv[1]); - if ((dst_end.payload_type = audio_name_to_type(argv[2])) == -1) + if ((dst_end->payload_type = audio_name_to_type(argv[2])) == -1) errx(1, "invalid output format '%s'", argv[2]); - rc = mgcp_transcoding_setup(&endp, &dst_end, &src_end); + rc = mgcp_transcoding_setup(&endp, dst_end, src_end); if (rc < 0) errx(1, "setup failed: %s", strerror(-rc)); - state = dst_end.rtp_process_data; + state = dst_end->rtp_process_data; OSMO_ASSERT(state != NULL); in_size = mgcp_transcoding_get_frame_size(state, 160, 0); OSMO_ASSERT(sizeof(buf) >= in_size + 12); + buf[1] = src_end->payload_type; + *(uint16_t*)(buf+2) = htons(1); + *(uint32_t*)(buf+4) = htonl(0); + *(uint32_t*)(buf+8) = htonl(0xaabbccdd); + while ((cc = read(0, buf + 12, in_size))) { + int cont; + int len; + if (cc != in_size) err(1, "read"); cc += 12; /* include RTP header */ - rc = mgcp_transcoding_process_rtp(&endp, &dst_end, - buf, &cc, sizeof(buf)); - if (rc < 0) - errx(1, "processing failed: %s", strerror(-rc)); + len = cc; + + do { + cont = mgcp_transcoding_process_rtp(&endp, dst_end, + buf, &len, sizeof(buf)); + if (cont == -EAGAIN) { + fprintf(stderr, "Got EAGAIN\n"); + break; + } + + if (cont < 0) + errx(1, "processing failed: %s", strerror(-cont)); + + len -= 12; /* ignore RTP header */ + + if (write(1, buf + 12, len) != len) + err(1, "write"); - cc -= 12; /* ignore RTP header */ - if (write(1, buf + 12, cc) != cc) - err(1, "write"); + len = cont; + } while (len > 0); } return 0; } diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h index b595aba..eb64e32 100644 --- a/openbsc/include/openbsc/mgcp.h +++ b/openbsc/include/openbsc/mgcp.h @@ -87,7 +87,8 @@ typedef int (*mgcp_policy)(struct mgcp_trunk_config *cfg, int endpoint, int stat typedef int (*mgcp_reset)(struct mgcp_trunk_config *cfg); typedef int (*mgcp_rqnt)(struct mgcp_endpoint *endp, char tone); -typedef int (*mgcp_processing)(struct mgcp_rtp_end *dst_end, +typedef int (*mgcp_processing)(struct mgcp_endpoint *endp, + struct mgcp_rtp_end *dst_end, char *data, int *len, int buf_size); typedef int (*mgcp_processing_setup)(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end, @@ -181,6 +182,8 @@ struct mgcp_config { struct mgcp_port_range transcoder_ports; int endp_dscp; + int bts_force_ptime; + mgcp_change change_cb; mgcp_policy policy_cb; mgcp_reset reset_cb; diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h index e74b9fa..c7bc2a8 100644 --- a/openbsc/include/openbsc/mgcp_internal.h +++ b/openbsc/include/openbsc/mgcp_internal.h @@ -90,6 +90,7 @@ struct mgcp_rtp_end { char *audio_name; char *subtype_name; int output_enabled; + int force_output_ptime; /* RTP patching */ int force_constant_ssrc; /* -1: always, 0: don't, 1: once */ @@ -202,7 +203,7 @@ void mgcp_state_calc_loss(struct mgcp_rtp_state *s, struct mgcp_rtp_end *, uint32_t mgcp_state_calc_jitter(struct mgcp_rtp_state *); /* payload processing default functions */ -int mgcp_rtp_processing_default(struct mgcp_rtp_end *dst_end, +int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end, char *data, int *len, int buf_size); int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp, diff --git a/openbsc/src/libmgcp/mgcp_network.c b/openbsc/src/libmgcp/mgcp_network.c index dcbb97a..42f0381 100644 --- a/openbsc/src/libmgcp/mgcp_network.c +++ b/openbsc/src/libmgcp/mgcp_network.c @@ -348,7 +348,7 @@ static int align_rtp_timestamp_offset(struct mgcp_endpoint *endp, return timestamp_error; } -int mgcp_rtp_processing_default(struct mgcp_rtp_end *dst_end, +int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end, char *data, int *len, int buf_size) { return 0; @@ -622,12 +622,28 @@ static int mgcp_send(struct mgcp_endpoint *endp, int dest, int is_rtp, if (!rtp_end->output_enabled) rtp_end->dropped_packets += 1; else if (is_rtp) { - mgcp_patch_and_count(endp, rtp_state, rtp_end, addr, buf, rc); - endp->cfg->rtp_processing_cb(rtp_end, buf, &rc, RTP_BUF_SIZE); - forward_data(rtp_end->rtp.fd, &endp->taps[tap_idx], buf, rc); - return mgcp_udp_send(rtp_end->rtp.fd, - &rtp_end->addr, - rtp_end->rtp_port, buf, rc); + int cont; + int nbytes = 0; + int len = rc; + mgcp_patch_and_count(endp, rtp_state, rtp_end, addr, buf, len); + do { + cont = endp->cfg->rtp_processing_cb(endp, rtp_end, + buf, &len, RTP_BUF_SIZE); + if (cont < 0) + break; + + forward_data(rtp_end->rtp.fd, &endp->taps[tap_idx], + buf, len); + rc = mgcp_udp_send(rtp_end->rtp.fd, + &rtp_end->addr, + rtp_end->rtp_port, buf, len); + + if (rc <= 0) + return rc; + nbytes += rc; + len = cont; + } while (len > 0); + return nbytes; } else if (!tcfg->omit_rtcp) { return mgcp_udp_send(rtp_end->rtcp.fd, &rtp_end->addr, diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c index 62bf481..f26587e 100644 --- a/openbsc/src/libmgcp/mgcp_protocol.c +++ b/openbsc/src/libmgcp/mgcp_protocol.c @@ -604,6 +604,12 @@ static int set_audio_info(struct mgcp_rtp_end *rtp, rtp->channels = channels; rtp->subtype_name = talloc_strdup(NULL, audio_codec); rtp->audio_name = talloc_strdup(NULL, audio_name); + + if (!strcmp(audio_codec, "G729")) { + rtp->frame_duration_num = 10; + rtp->frame_duration_den = 1000; + } + if (channels != 1) LOGP(DMGCP, LOGL_NOTICE, "Channels != 1 in SDP: '%s'\n", audio_name); @@ -916,11 +922,16 @@ mgcp_header_done: set_audio_info(&endp->bts_end, tcfg->audio_payload, tcfg->audio_name); endp->bts_end.fmtp_extra = talloc_strdup(tcfg->endpoints, tcfg->audio_fmtp_extra); - if (have_sdp) { + if (have_sdp) parse_sdp_data(&endp->net_end, p); - setup_rtp_processing(endp); + + if (p->cfg->bts_force_ptime) { + endp->bts_end.packet_duration_ms = p->cfg->bts_force_ptime; + endp->bts_end.force_output_ptime = 1; } + setup_rtp_processing(endp); + /* policy CB */ if (p->cfg->policy_cb) { int rc; diff --git a/openbsc/src/libmgcp/mgcp_vty.c b/openbsc/src/libmgcp/mgcp_vty.c index 953d34b..f1afa95 100644 --- a/openbsc/src/libmgcp/mgcp_vty.c +++ b/openbsc/src/libmgcp/mgcp_vty.c @@ -362,6 +362,26 @@ ALIAS_DEPRECATED(cfg_mgcp_rtp_ip_dscp, cfg_mgcp_rtp_ip_tos_cmd, RTP_STR "Apply IP_TOS to the audio stream\n" "The DSCP value\n") +#define FORCE_PTIME_STR "Force a fixed ptime for packets sent to the BTS" +DEFUN(cfg_mgcp_rtp_force_ptime, + cfg_mgcp_rtp_force_ptime_cmd, + "rtp force-ptime (10|20|40)", + RTP_STR FORCE_PTIME_STR + "The required ptime (packet duration) in ms\n") +{ + g_cfg->bts_force_ptime = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_no_rtp_force_ptime, + cfg_mgcp_no_rtp_force_ptime_cmd, + "no rtp force-ptime", + NO_STR RTP_STR FORCE_PTIME_STR) +{ + g_cfg->bts_force_ptime = 0; + return CMD_SUCCESS; +} + DEFUN(cfg_mgcp_sdp_fmtp_extra, cfg_mgcp_sdp_fmtp_extra_cmd, "sdp audio fmtp-extra .NAME", @@ -1084,6 +1104,8 @@ int mgcp_vty_init(void) install_element(MGCP_NODE, &cfg_mgcp_rtp_transcoder_base_cmd); install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_dscp_cmd); install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_tos_cmd); + install_element(MGCP_NODE, &cfg_mgcp_rtp_force_ptime_cmd); + install_element(MGCP_NODE, &cfg_mgcp_no_rtp_force_ptime_cmd); install_element(MGCP_NODE, &cfg_mgcp_rtp_keepalive_cmd); install_element(MGCP_NODE, &cfg_mgcp_rtp_keepalive_once_cmd); install_element(MGCP_NODE, &cfg_mgcp_no_rtp_keepalive_cmd); diff --git a/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c b/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c index ea4bd74..edd3178 100644 --- a/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c +++ b/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c @@ -70,6 +70,14 @@ struct mgcp_process_rtp_state { } dst; size_t dst_frame_size; size_t dst_samples_per_frame; + int dst_packet_duration; + + int is_running; + uint16_t next_seq; + uint32_t next_time; + int16_t samples[10*160]; + size_t sample_cnt; + size_t sample_offs; }; int mgcp_transcoding_get_frame_size(void *state_, int nsamples, int dst) @@ -302,6 +310,9 @@ int mgcp_transcoding_setup(struct mgcp_endpoint *endp, break; } + if (dst_end->force_output_ptime) + state->dst_packet_duration = mgcp_rtp_packet_duration(endp, dst_end); + LOGP(DMGCP, LOGL_INFO, "Initialized RTP processing on: 0x%x " "conv: %d (%d, %d, %s) -> %d (%d, %d, %s)\n", @@ -330,44 +341,21 @@ void mgcp_transcoding_net_downlink_format(struct mgcp_endpoint *endp, *audio_name = endp->net_end.audio_name; } - -int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp, - struct mgcp_rtp_end *dst_end, - char *data, int *len, int buf_size) +static int decode_audio(struct mgcp_process_rtp_state *state, + uint8_t **src, size_t *nbytes) { - struct mgcp_process_rtp_state *state = dst_end->rtp_process_data; - size_t rtp_hdr_size = 12; - char *payload_data = data + rtp_hdr_size; - int payload_len = *len - rtp_hdr_size; - size_t sample_cnt = 0; - size_t sample_idx; - int16_t samples[10*160]; - uint8_t *src = (uint8_t *)payload_data; - uint8_t *dst = (uint8_t *)payload_data; - size_t nbytes = payload_len; - size_t frame_remainder; - - if (!state) - return 0; - - if (state->src_fmt == state->dst_fmt) - return 0; - - /* TODO: check payload type (-> G.711 comfort noise) */ - - /* Decode src into samples */ - while (nbytes >= state->src_frame_size) { - if (sample_cnt + state->src_samples_per_frame > ARRAY_SIZE(samples)) { + while (*nbytes >= state->src_frame_size) { + if (state->sample_cnt + state->src_samples_per_frame > ARRAY_SIZE(state->samples)) { LOGP(DMGCP, LOGL_ERROR, "Sample buffer too small: %d > %d.\n", - sample_cnt + state->src_samples_per_frame, - ARRAY_SIZE(samples)); + state->sample_cnt + state->src_samples_per_frame, + ARRAY_SIZE(state->samples)); return -ENOSPC; } switch (state->src_fmt) { case AF_GSM: if (gsm_decode(state->src.gsm_handle, - (gsm_byte *)src, samples + sample_cnt) < 0) { + (gsm_byte *)*src, state->samples + state->sample_cnt) < 0) { LOGP(DMGCP, LOGL_ERROR, "Failed to decode GSM.\n"); return -EINVAL; @@ -375,54 +363,44 @@ int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp, break; #ifdef HAVE_BCG729 case AF_G729: - bcg729Decoder(state->src.g729_dec, src, 0, samples + sample_cnt); + bcg729Decoder(state->src.g729_dec, *src, 0, state->samples + state->sample_cnt); break; #endif case AF_PCMA: - alaw_decode(src, samples + sample_cnt, + alaw_decode(*src, state->samples + state->sample_cnt, state->src_samples_per_frame); break; case AF_S16: - memmove(samples + sample_cnt, src, + memmove(state->samples + state->sample_cnt, *src, state->src_frame_size); break; case AF_L16: - l16_decode(src, samples + sample_cnt, + l16_decode(*src, state->samples + state->sample_cnt, state->src_samples_per_frame); break; default: break; } - src += state->src_frame_size; - nbytes -= state->src_frame_size; - sample_cnt += state->src_samples_per_frame; - } - - /* Add silence if necessary */ - frame_remainder = sample_cnt % state->dst_samples_per_frame; - if (frame_remainder) { - size_t silence = state->dst_samples_per_frame - frame_remainder; - if (sample_cnt + silence > ARRAY_SIZE(samples)) { - LOGP(DMGCP, LOGL_ERROR, - "Sample buffer too small for silence: %d > %d.\n", - sample_cnt + silence, - ARRAY_SIZE(samples)); - return -ENOSPC; - } - - while (silence > 0) { - samples[sample_cnt] = 0; - sample_cnt += 1; - silence -= 1; - } + *src += state->src_frame_size; + *nbytes -= state->src_frame_size; + state->sample_cnt += state->src_samples_per_frame; } + return 0; +} +static int encode_audio(struct mgcp_process_rtp_state *state, + uint8_t *dst, size_t buf_size, size_t max_samples) +{ + int nbytes = 0; + size_t nsamples = 0; /* Encode samples into dst */ - sample_idx = 0; - nbytes = 0; - while (sample_idx + state->dst_samples_per_frame <= sample_cnt) { + while (nsamples + state->dst_samples_per_frame <= max_samples) { if (nbytes + state->dst_frame_size > buf_size) { - LOGP(DMGCP, LOGL_ERROR, + if (nbytes > 0) + break; + + /* Not even one frame fits into the buffer */ + LOGP(DMGCP, LOGL_INFO, "Encoding (RTP) buffer too small: %d > %d.\n", nbytes + state->dst_frame_size, buf_size); return -ENOSPC; @@ -430,23 +408,24 @@ int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp, switch (state->dst_fmt) { case AF_GSM: gsm_encode(state->dst.gsm_handle, - samples + sample_idx, dst); + state->samples + state->sample_offs, dst); break; #ifdef HAVE_BCG729 case AF_G729: bcg729Encoder(state->dst.g729_enc, - samples + sample_idx, dst); + state->samples + state->sample_offs, dst); break; #endif case AF_PCMA: - alaw_encode(samples + sample_idx, dst, + alaw_encode(state->samples + state->sample_offs, dst, state->src_samples_per_frame); break; case AF_S16: - memmove(dst, samples + sample_idx, state->dst_frame_size); + memmove(dst, state->samples + state->sample_offs, + state->dst_frame_size); break; case AF_L16: - l16_encode(samples + sample_idx, dst, + l16_encode(state->samples + state->sample_offs, dst, state->src_samples_per_frame); break; default: @@ -454,19 +433,121 @@ int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp, } dst += state->dst_frame_size; nbytes += state->dst_frame_size; - sample_idx += state->dst_samples_per_frame; + state->sample_offs += state->dst_samples_per_frame; + nsamples += state->dst_samples_per_frame; } + state->sample_cnt -= nsamples; + return nbytes; +} - *len = rtp_hdr_size + nbytes; - /* Patch payload type */ - data[1] = (data[1] & 0x80) | (dst_end->payload_type & 0x7f); +int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp, + struct mgcp_rtp_end *dst_end, + char *data, int *len, int buf_size) +{ + struct mgcp_process_rtp_state *state = dst_end->rtp_process_data; + size_t rtp_hdr_size = 12; + char *payload_data = data + rtp_hdr_size; + int payload_len = *len - rtp_hdr_size; + // size_t sample_idx; + uint8_t *src = (uint8_t *)payload_data; + uint8_t *dst = (uint8_t *)payload_data; + size_t nbytes = payload_len; + // size_t frame_remainder; + size_t nsamples; + size_t max_samples; + uint32_t ts_no; + int rc; - /* TODO: remove me - fprintf(stderr, "sample_cnt = %d, sample_idx = %d, plen = %d -> %d, " - "hdr_size = %d, len = %d, pt = %d\n", - sample_cnt, sample_idx, payload_len, nbytes, rtp_hdr_size, *len, - data[1]); - */ + if (!state) + return 0; - return 0; + if (state->src_fmt == state->dst_fmt) { + if (!state->dst_packet_duration) + return 0; + + /* TODO: repackage without transcoding */ + } + + /* If the remaining samples do not fit into a fixed ptime, + * a) discard them, if the next packet is much later + * b) add silence and * send it, if the current packet is not + * yet too late + * c) append the sample data, if the timestamp matches exactly + */ + + /* TODO: check payload type (-> G.711 comfort noise) */ + + if (payload_len > 0) { + ts_no = ntohl(*(uint32_t*)(data+4)); + if (!state->is_running) + state->next_seq = ntohs(*(uint32_t*)(data+4)); + + state->is_running = 1; + + if (state->sample_cnt > 0) { + int32_t delta = ts_no - state->next_time; + /* TODO: check sequence? reordering? packet loss? */ + + if (delta > state->sample_cnt) + /* There is a time gap between the last packet + * and the current one. Just discard the + * partial data that is left in the buffer. + * TODO: This can be improved by adding silence + * instead if the delta is small enough. + */ + state->sample_cnt = 0; + else if (delta < 0) { + LOGP(DMGCP, LOGL_NOTICE, + "RTP time jumps backwards, delta = %d, " + "discarding buffered samples\n", + delta); + state->sample_cnt = 0; + state->sample_offs = 0; + return -EAGAIN; + } + + /* Make sure the samples start without offset */ + fprintf(stderr, "Moving %d samples to buffer start (offset %d)\n", state->sample_cnt, state->sample_offs); + if (state->sample_offs && state->sample_cnt) + memmove(&state->samples[0], + &state->samples[state->sample_offs], + state->sample_cnt * sizeof(state->samples[0])); + } + + state->sample_offs = 0; + + /* Append decoded audio to samples */ + decode_audio(state, &src, &nbytes); + + if (nbytes > 0) + LOGP(DMGCP, LOGL_NOTICE, + "Skipped audio frame in RTP packet: %d octets\n", + nbytes); + } else + ts_no = state->next_time; + + if (state->sample_cnt < state->dst_packet_duration) + return -EAGAIN; + + max_samples = + state->dst_packet_duration ? + state->dst_packet_duration : state->sample_cnt; + + nsamples = state->sample_cnt; + + rc = encode_audio(state, dst, buf_size, max_samples); + if (rc <= 0) + return rc; + + nsamples -= state->sample_cnt; + fprintf(stderr, "Wrote %d samples to buffer (offset %d)\n", nsamples, state->sample_offs); + + *len = rtp_hdr_size + rc; + *(uint16_t*)(data+2) = htonl(state->next_seq); + *(uint32_t*)(data+4) = htonl(ts_no); + + state->next_seq += 1; + state->next_time = ts_no + nsamples; + + return nsamples ? rtp_hdr_size : 0; } -- 1.7.9.5 From jerlbeck at sysmocom.de Mon May 12 10:39:04 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Mon, 12 May 2014 12:39:04 +0200 Subject: [PATCH 08/11] mgcp: Extend the CLI transcoding tool by ptime conversion In-Reply-To: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1399891147-31419-8-git-send-email-jerlbeck@sysmocom.de> This modification allows it to set the number of samples per packet that is written to the output. Sponsored-by: On-Waves ehf --- openbsc/contrib/testconv/testconv_main.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/openbsc/contrib/testconv/testconv_main.c b/openbsc/contrib/testconv/testconv_main.c index aee7304..e74c686 100644 --- a/openbsc/contrib/testconv/testconv_main.c +++ b/openbsc/contrib/testconv/testconv_main.c @@ -46,6 +46,10 @@ int main(int argc, char **argv) struct mgcp_endpoint endp = {0}; struct mgcp_process_rtp_state *state; int in_size; + int in_samples = 160; + int out_samples = 0; + uint32_t ts = 0; + uint16_t seq = 0; osmo_init_logging(&log_info); @@ -58,12 +62,20 @@ int main(int argc, char **argv) src_end = &endp.net_end; if (argc <= 2) - errx(1, "Usage: {gsm|g729|pcma|l16} {gsm|g729|pcma|l16}"); + errx(1, "Usage: {gsm|g729|pcma|l16} {gsm|g729|pcma|l16} [SPP]"); if ((src_end->payload_type = audio_name_to_type(argv[1])) == -1) errx(1, "invalid input format '%s'", argv[1]); if ((dst_end->payload_type = audio_name_to_type(argv[2])) == -1) errx(1, "invalid output format '%s'", argv[2]); + if (argc > 3) + out_samples = atoi(argv[3]); + + if (out_samples) { + dst_end->frame_duration_den = dst_end->rate; + dst_end->frame_duration_num = out_samples; + dst_end->frames_per_packet = 1; + } rc = mgcp_transcoding_setup(&endp, dst_end, src_end); if (rc < 0) @@ -72,7 +84,7 @@ int main(int argc, char **argv) state = dst_end->rtp_process_data; OSMO_ASSERT(state != NULL); - in_size = mgcp_transcoding_get_frame_size(state, 160, 0); + in_size = mgcp_transcoding_get_frame_size(state, in_samples, 0); OSMO_ASSERT(sizeof(buf) >= in_size + 12); buf[1] = src_end->payload_type; @@ -87,13 +99,19 @@ int main(int argc, char **argv) if (cc != in_size) err(1, "read"); + *(uint16_t*)(buf+2) = htonl(seq); + *(uint32_t*)(buf+4) = htonl(ts); + + seq += 1; + ts += in_samples; + cc += 12; /* include RTP header */ len = cc; do { cont = mgcp_transcoding_process_rtp(&endp, dst_end, - buf, &len, sizeof(buf)); + buf, &len, sizeof(buf)); if (cont == -EAGAIN) { fprintf(stderr, "Got EAGAIN\n"); break; -- 1.7.9.5 From jerlbeck at sysmocom.de Mon May 12 10:39:05 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Mon, 12 May 2014 12:39:05 +0200 Subject: [PATCH 09/11] mgcp/test: Add test cases for transcoding and repacking In-Reply-To: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1399891147-31419-9-git-send-email-jerlbeck@sysmocom.de> This patch adds test cases for transcoding and repacking. Sponsored-by: On-Waves ehf --- openbsc/tests/atlocal.in | 1 + openbsc/tests/mgcp/Makefile.am | 19 +- openbsc/tests/mgcp/mgcp_transcoding_test.c | 377 +++++++++++++++++++ openbsc/tests/mgcp/mgcp_transcoding_test.ok | 534 +++++++++++++++++++++++++++ openbsc/tests/testsuite.at | 7 + 5 files changed, 935 insertions(+), 3 deletions(-) create mode 100644 openbsc/tests/mgcp/mgcp_transcoding_test.c create mode 100644 openbsc/tests/mgcp/mgcp_transcoding_test.ok diff --git a/openbsc/tests/atlocal.in b/openbsc/tests/atlocal.in index 4635113..542a78e 100644 --- a/openbsc/tests/atlocal.in +++ b/openbsc/tests/atlocal.in @@ -1,3 +1,4 @@ enable_nat_test='@osmo_ac_build_nat@' enable_smpp_test='@osmo_ac_build_smpp@' enable_bsc_test='@osmo_ac_build_bsc@' +enable_mgcp_transcoding_test='@osmo_ac_mgcp_transcoding@' diff --git a/openbsc/tests/mgcp/Makefile.am b/openbsc/tests/mgcp/Makefile.am index 71bf8c0..81f28ae 100644 --- a/openbsc/tests/mgcp/Makefile.am +++ b/openbsc/tests/mgcp/Makefile.am @@ -1,11 +1,15 @@ -AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOSCCP_CFLAGS) $(COVERAGE_CFLAGS) +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_srcdir) +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOSCCP_CFLAGS) $(COVERAGE_CFLAGS) $(LIBBCG729_CFLAGS) AM_LDFLAGS = $(COVERAGE_LDFLAGS) -EXTRA_DIST = mgcp_test.ok +EXTRA_DIST = mgcp_test.ok mgcp_transcoding_test.ok noinst_PROGRAMS = mgcp_test +if BUILD_MGCP_TRANSCODING +noinst_PROGRAMS += mgcp_transcoding_test +endif + mgcp_test_SOURCES = mgcp_test.c mgcp_test_LDADD = $(top_builddir)/src/libbsc/libbsc.a \ @@ -13,3 +17,12 @@ mgcp_test_LDADD = $(top_builddir)/src/libbsc/libbsc.a \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOCORE_LIBS) -lrt -lm $(LIBOSMOSCCP_LIBS) $(LIBOSMOVTY_LIBS) \ $(LIBRARY_DL) + +mgcp_transcoding_test_SOURCES = mgcp_transcoding_test.c $(top_builddir)/src/osmo-bsc_mgcp/mgcp_transcode.c + +mgcp_transcoding_test_LDADD = \ + $(top_builddir)/src/libbsc/libbsc.a \ + $(top_builddir)/src/libmgcp/libmgcp.a \ + $(top_builddir)/src/libcommon/libcommon.a \ + $(LIBOSMOCORE_LIBS) $(LIBBCG729_LIBS) -lrt -lm $(LIBOSMOSCCP_LIBS) $(LIBOSMOVTY_LIBS) \ + $(LIBRARY_DL) diff --git a/openbsc/tests/mgcp/mgcp_transcoding_test.c b/openbsc/tests/mgcp/mgcp_transcoding_test.c new file mode 100644 index 0000000..a1af157 --- /dev/null +++ b/openbsc/tests/mgcp/mgcp_transcoding_test.c @@ -0,0 +1,377 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "bscconfig.h" +#ifndef BUILD_MGCP_TRANSCODING +#error "Requires MGCP transcoding enabled (see --enable-mgcp-transcoding)" +#endif + +#include "src/osmo-bsc_mgcp/mgcp_transcode.h" + +uint8_t *audio_frame_l16[] = { +}; + +struct rtp_packets { + float t; + int len; + char *data; +}; + +struct rtp_packets audio_packets_l16[] = { + /* RTP: SeqNo=1, TS=160 */ + {0.020000, 332, + "\x80\x0B\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + }, +}; + +struct rtp_packets audio_packets_gsm[] = { + /* RTP: SeqNo=1, TS=160 */ + {0.020000, 45, + "\x80\x03\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44" + "\xD4\x7C\xE3\xE9\x62\x50\x39\xF0\xF8\xB4\x68\xEA\x6C\x0E\x81\x1B" + "\x56\x2A\xD5\xBC\x69\x9C\xD1\xF0\x66\x7A\xEC\x49\x7A\x33\x3D\x0A" + "\xDE" + }, +}; + +struct rtp_packets audio_packets_gsm_invalid_size[] = { + /* RTP: SeqNo=1, TS=160 */ + {0.020000, 41, + "\x80\x03\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44" + "\xD4\x7C\xE3\xE9\x62\x50\x39\xF0\xF8\xB4\x68\xEA\x6C\x0E\x81\x1B" + "\x56\x2A\xD5\xBC\x69\x9C\xD1\xF0\x66\x7A\xEC\x49\x7A\x33\x3D\x0A" + "\xDE" + }, +}; + +struct rtp_packets audio_packets_gsm_invalid_data[] = { + /* RTP: SeqNo=1, TS=160 */ + {0.020000, 45, + "\x80\x03\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44" + "\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE" + "\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE" + "\xEE" + }, +}; + +struct rtp_packets audio_packets_gsm_invalid_ptype[] = { + /* RTP: SeqNo=1, TS=160 */ + {0.020000, 45, + "\x80\x08\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44" + "\xD4\x7C\xE3\xE9\x62\x50\x39\xF0\xF8\xB4\x68\xEA\x6C\x0E\x81\x1B" + "\x56\x2A\xD5\xBC\x69\x9C\xD1\xF0\x66\x7A\xEC\x49\x7A\x33\x3D\x0A" + "\xDE" + }, +}; + +struct rtp_packets audio_packets_g729[] = { + /* RTP: SeqNo=1, TS=160 */ + {0.020000, 32, + "\x80\x12\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44" + "\xAF\xC2\x81\x40\x00\xFA\xCE\xA4\x21\x7C\xC5\xC3\x4F\xA5\x98\xF5" + "\xB2\x95\xC4\xAD" + }, +}; + +struct rtp_packets audio_packets_pcma[] = { + /* RTP: SeqNo=1, TS=160 */ + {0.020000, 172, + "\x80\x08\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44" + "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25" + "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25" + "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25" + "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25" + "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25" + "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25" + "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25" + "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25" + "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25" + "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25" + }, +}; + + + +static int audio_name_to_type(const char *name) +{ + if (!strcasecmp(name, "gsm")) + return 3; +#ifdef HAVE_BCG729 + else if (!strcasecmp(name, "g729")) + return 18; +#endif + else if (!strcasecmp(name, "pcma")) + return 8; + else if (!strcasecmp(name, "l16")) + return 11; + return -1; +} + +int mgcp_get_trans_frame_size(void *state_, int nsamples, int dst); + +static int transcode_test(const char *srcfmt, const char *dstfmt, + uint8_t *src_pkts, size_t src_pkt_size) +{ + char buf[4096] = {0x80, 0}; + int rc; + struct mgcp_rtp_end *dst_end; + struct mgcp_rtp_end *src_end; + struct mgcp_trunk_config tcfg = {{0}}; + struct mgcp_endpoint endp = {0}; + struct mgcp_process_rtp_state *state; + int in_size; + int in_samples = 160; + int len, cont; + + printf("== Transcoding test ==\n"); + printf("converting %s -> %s\n", srcfmt, dstfmt); + + tcfg.endpoints = &endp; + tcfg.number_endpoints = 1; + endp.tcfg = &tcfg; + mgcp_free_endp(&endp); + + dst_end = &endp.bts_end; + src_end = &endp.net_end; + + src_end->payload_type = audio_name_to_type(srcfmt); + dst_end->payload_type = audio_name_to_type(dstfmt); + + rc = mgcp_transcoding_setup(&endp, dst_end, src_end); + if (rc < 0) + errx(1, "setup failed: %s", strerror(-rc)); + + state = dst_end->rtp_process_data; + OSMO_ASSERT(state != NULL); + + in_size = mgcp_transcoding_get_frame_size(state, in_samples, 0); + OSMO_ASSERT(sizeof(buf) >= in_size + 12); + + memcpy(buf, src_pkts, src_pkt_size); + + len = src_pkt_size; + + cont = mgcp_transcoding_process_rtp(&endp, dst_end, + buf, &len, sizeof(buf)); + if (cont < 0) + errx(1, "processing failed: %s", strerror(-cont)); + + if (len < 24) { + printf("encoded: %s\n", osmo_hexdump((unsigned char *)buf, len)); + } else { + const char *str = osmo_hexdump((unsigned char *)buf, len); + int i = 0; + const int prefix = 4; + const int cutlen = 48; + int nchars = 0; + + printf("encoded:\n"); + do { + nchars = printf("% *s%-.*s", prefix, "", cutlen, str + i); + i += nchars - prefix; + printf("\n"); + } while (nchars - prefix >= cutlen); + } + return 0; +} + +static int test_repacking(int in_samples, int out_samples, int no_transcode) +{ + char buf[4096] = {0x80, 0}; + int cc, rc; + struct mgcp_rtp_end *dst_end; + struct mgcp_rtp_end *src_end; + struct mgcp_config *cfg; + struct mgcp_trunk_config tcfg = {{0}}; + struct mgcp_endpoint endp = {0}; + struct mgcp_process_rtp_state *state; + int in_cnt; + int out_size; + int in_size; + uint32_t ts = 0; + uint16_t seq = 0; + const char *srcfmt = "pcma"; + const char *dstfmt = no_transcode ? "pcma" : "l16"; + + cfg = mgcp_config_alloc(); + + tcfg.endpoints = &endp; + tcfg.number_endpoints = 1; + tcfg.cfg = cfg; + endp.tcfg = &tcfg; + endp.cfg = cfg; + mgcp_free_endp(&endp); + + dst_end = &endp.bts_end; + src_end = &endp.net_end; + + printf("== Transcoding test ==\n"); + printf("converting %s -> %s\n", srcfmt, dstfmt); + + src_end->payload_type = audio_name_to_type(srcfmt); + dst_end->payload_type = audio_name_to_type(dstfmt); + + if (out_samples) { + dst_end->frame_duration_den = dst_end->rate; + dst_end->frame_duration_num = out_samples; + dst_end->frames_per_packet = 1; + dst_end->force_output_ptime = 1; + } + + rc = mgcp_transcoding_setup(&endp, dst_end, src_end); + if (rc < 0) + errx(1, "setup failed: %s", strerror(-rc)); + + state = dst_end->rtp_process_data; + OSMO_ASSERT(state != NULL); + + in_size = mgcp_transcoding_get_frame_size(state, in_samples, 0); + OSMO_ASSERT(sizeof(buf) >= in_size + 12); + + out_size = mgcp_transcoding_get_frame_size(state, -1, 1); + OSMO_ASSERT(sizeof(buf) >= out_size + 12); + + buf[1] = src_end->payload_type; + *(uint16_t*)(buf+2) = htons(1); + *(uint32_t*)(buf+4) = htonl(0); + *(uint32_t*)(buf+8) = htonl(0xaabbccdd); + + for (in_cnt = 0; in_cnt < 16; in_cnt++) { + int cont; + int len; + + /* fake PCMA data */ + printf("generating %d %s input samples\n", in_samples, srcfmt); + for (cc = 0; cc < in_samples; cc++) + buf[12+cc] = cc; + + *(uint16_t*)(buf+2) = htonl(seq); + *(uint32_t*)(buf+4) = htonl(ts); + + seq += 1; + ts += in_samples; + + cc += 12; /* include RTP header */ + + len = cc; + + do { + cont = mgcp_transcoding_process_rtp(&endp, dst_end, + buf, &len, sizeof(buf)); + if (cont == -EAGAIN) { + fprintf(stderr, "Got EAGAIN\n"); + break; + } + + if (cont < 0) + errx(1, "processing failed: %s", strerror(-cont)); + + len -= 12; /* ignore RTP header */ + + printf("got %d %s output frames (%d octets)\n", + len / out_size, dstfmt, len); + + len = cont; + } while (len > 0); + } + return 0; +} + +int main(int argc, char **argv) +{ + osmo_init_logging(&log_info); + + printf("=== Transcoding Good Cases ===\n"); + + transcode_test("l16", "l16", + (uint8_t *)audio_packets_l16[0].data, + audio_packets_l16[0].len); + transcode_test("l16", "gsm", + (uint8_t *)audio_packets_l16[0].data, + audio_packets_l16[0].len); + transcode_test("l16", "pcma", + (uint8_t *)audio_packets_l16[0].data, + audio_packets_l16[0].len); + transcode_test("gsm", "l16", + (uint8_t *)audio_packets_gsm[0].data, + audio_packets_gsm[0].len); + transcode_test("gsm", "gsm", + (uint8_t *)audio_packets_gsm[0].data, + audio_packets_gsm[0].len); + transcode_test("gsm", "pcma", + (uint8_t *)audio_packets_gsm[0].data, + audio_packets_gsm[0].len); + transcode_test("pcma", "l16", + (uint8_t *)audio_packets_pcma[0].data, + audio_packets_pcma[0].len); + transcode_test("pcma", "gsm", + (uint8_t *)audio_packets_pcma[0].data, + audio_packets_pcma[0].len); + transcode_test("pcma", "pcma", + (uint8_t *)audio_packets_pcma[0].data, + audio_packets_pcma[0].len); + + printf("=== Transcoding Bad Cases ===\n"); + + printf("Invalid size:\n"); + transcode_test("gsm", "pcma", + (uint8_t *)audio_packets_gsm_invalid_size[0].data, + audio_packets_gsm_invalid_size[0].len); + + printf("Invalid data:\n"); + transcode_test("gsm", "pcma", + (uint8_t *)audio_packets_gsm_invalid_data[0].data, + audio_packets_gsm_invalid_data[0].len); + + printf("Invalid payload type:\n"); + transcode_test("gsm", "pcma", + (uint8_t *)audio_packets_gsm_invalid_ptype[0].data, + audio_packets_gsm_invalid_ptype[0].len); + + printf("=== Repacking ===\n"); + + test_repacking(160, 160, 0); + test_repacking(160, 160, 1); + test_repacking(160, 80, 0); + test_repacking(160, 80, 1); + test_repacking(160, 320, 0); + test_repacking(160, 320, 1); + test_repacking(160, 240, 0); + test_repacking(160, 240, 1); + test_repacking(160, 100, 0); + test_repacking(160, 100, 1); + + return 0; +} + diff --git a/openbsc/tests/mgcp/mgcp_transcoding_test.ok b/openbsc/tests/mgcp/mgcp_transcoding_test.ok new file mode 100644 index 0000000..189d079 --- /dev/null +++ b/openbsc/tests/mgcp/mgcp_transcoding_test.ok @@ -0,0 +1,534 @@ +=== Transcoding Good Cases === +== Transcoding test == +converting l16 -> l16 +encoded: + 80 0b 00 01 00 00 00 a0 11 22 33 44 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed +== Transcoding test == +converting l16 -> gsm +encoded: + 80 0b 00 00 00 00 00 a0 11 22 33 44 d4 7c e3 e9 + 62 50 39 f0 f8 b4 68 ea 6c 0e 81 1b 56 2a d5 bc + 69 9c d1 f0 66 7a ec 49 7a 33 3d 0a de +== Transcoding test == +converting l16 -> pcma +encoded: + 80 0b 00 00 00 00 00 a0 11 22 33 44 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 +== Transcoding test == +converting gsm -> l16 +encoded: + 80 03 00 00 00 00 00 a0 11 22 33 44 00 00 54 00 + 59 f0 34 20 c4 c8 b9 f8 e2 18 f1 e8 f2 28 f0 e0 + 46 08 4f 80 2c a0 a9 c8 80 00 c0 58 3f 80 63 c0 + 24 b8 fa b8 f6 88 0b a0 c8 70 a8 b0 c8 c0 3b a8 + 66 a0 2e 38 d1 f8 98 98 aa 18 e8 30 26 a0 37 40 + 37 e8 17 00 ee 50 b7 80 b1 88 de 28 18 40 45 b0 + 4f 48 21 d8 df 78 ae 68 ab 98 d6 b8 18 18 48 90 + 4e 70 27 40 e8 10 b5 b0 ac 80 d4 60 14 50 48 48 + 50 10 2a 00 ec 08 ba 00 af 58 d1 c0 10 60 45 c8 + 54 10 30 78 f1 a8 bb 18 ad 48 ce 30 0a e8 3f 30 + 4f 10 32 18 f6 18 bf 20 ac 30 cd 80 0b d0 43 d8 + 55 e0 34 a0 f5 78 bc 98 ad 98 cd c8 0a 80 40 58 + 51 c0 35 40 f9 60 c1 68 ac c8 cb 38 08 00 40 98 + 51 e0 34 d8 fa 28 c2 f0 ae 40 c7 70 02 d0 3c a8 + 54 78 38 a0 fc 68 c2 08 ad 50 c7 78 01 60 39 c0 + 51 38 3a e8 00 e8 c6 38 ab d8 c4 00 fe 08 39 18 + 50 30 39 50 01 d8 ca 70 b1 80 c4 c8 fc 58 36 40 + 51 d8 3b 08 02 80 c8 58 b0 60 c5 a8 fb d0 33 e8 + 4e 80 3c e0 06 10 cb 90 ae 48 c2 60 f9 58 34 08 + 4d a0 3a a8 06 48 cf 80 b4 60 c3 e8 f7 90 30 18 + 4d a0 3b 98 07 90 cf 18 b4 68 c4 88 +== Transcoding test == +converting gsm -> gsm +encoded: + 80 03 00 01 00 00 00 a0 11 22 33 44 d4 7c e3 e9 + 62 50 39 f0 f8 b4 68 ea 6c 0e 81 1b 56 2a d5 bc + 69 9c d1 f0 66 7a ec 49 7a 33 3d 0a de +== Transcoding test == +converting gsm -> pcma +encoded: + 80 03 00 00 00 00 00 a0 11 22 33 44 d5 a0 a3 bf + 38 24 08 19 1e 1b a4 a6 b3 20 2a 3a ba ad b7 60 + 17 92 3e 20 3e b8 ac b2 32 2c 20 02 b6 be be 82 + 04 27 26 35 8d a4 a6 b5 35 21 20 31 8d a7 a6 b6 + 02 27 21 30 81 a7 a1 b0 06 24 21 32 85 a4 a0 bd + 19 24 21 3d 90 ba a6 bc 16 25 21 3c 92 a5 a0 bf + 10 25 21 3c 90 a5 a1 bf 6f 3a 21 3f 95 a5 a1 bf + 62 3b 21 39 f3 bb a0 b9 79 3b 21 39 c3 b9 a1 b8 + db 39 20 3b 4a b9 a1 b9 c8 3f 26 38 78 be a1 b8 + f1 3e 26 38 65 bc a6 bb ed 3f 21 3b 6f bf a6 b8 + ec 3d 27 3b 15 bd a6 b8 eb 3d 27 38 +== Transcoding test == +converting pcma -> l16 +encoded: + 80 08 00 00 00 00 00 a0 11 22 33 44 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 +== Transcoding test == +converting pcma -> gsm +encoded: + 80 08 00 00 00 00 00 a0 11 22 33 44 d4 b9 f4 5d + d9 50 5a e1 a0 cd 76 ea 52 0e 87 53 ad d4 ea a2 + 0a 63 ca e9 60 79 e2 2a 25 d2 c0 f3 39 +== Transcoding test == +converting pcma -> pcma +encoded: + 80 08 00 01 00 00 00 a0 11 22 33 44 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 +=== Transcoding Bad Cases === +Invalid size: +== Transcoding test == +converting gsm -> pcma +encoded: + 80 03 00 01 00 00 00 a0 11 22 33 44 d4 7c e3 e9 + 62 50 39 f0 f8 b4 68 ea 6c 0e 81 1b 56 2a d5 bc + 69 9c d1 f0 66 7a ec 49 7a +Invalid data: +== Transcoding test == +converting gsm -> pcma +encoded: + 80 03 00 01 00 00 00 a0 11 22 33 44 ee ee ee ee + ee ee ee ee ee ee ee ee ee ee ee ee ee ee ee ee + ee ee ee ee ee ee ee ee ee ee ee ee ee +Invalid payload type: +== Transcoding test == +converting gsm -> pcma +encoded: + 80 08 00 00 00 00 00 a0 11 22 33 44 d5 a0 a3 bf + 38 24 08 19 1e 1b a4 a6 b3 20 2a 3a ba ad b7 60 + 17 92 3e 20 3e b8 ac b2 32 2c 20 02 b6 be be 82 + 04 27 26 35 8d a4 a6 b5 35 21 20 31 8d a7 a6 b6 + 02 27 21 30 81 a7 a1 b0 06 24 21 32 85 a4 a0 bd + 19 24 21 3d 90 ba a6 bc 16 25 21 3c 92 a5 a0 bf + 10 25 21 3c 90 a5 a1 bf 6f 3a 21 3f 95 a5 a1 bf + 62 3b 21 39 f3 bb a0 b9 79 3b 21 39 c3 b9 a1 b8 + db 39 20 3b 4a b9 a1 b9 c8 3f 26 38 78 be a1 b8 + f1 3e 26 38 65 bc a6 bb ed 3f 21 3b 6f bf a6 b8 + ec 3d 27 3b 15 bd a6 b8 eb 3d 27 38 +=== Repacking === +== Transcoding test == +converting pcma -> l16 +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +== Transcoding test == +converting pcma -> pcma +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +== Transcoding test == +converting pcma -> l16 +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +== Transcoding test == +converting pcma -> pcma +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +== Transcoding test == +converting pcma -> l16 +generating 160 pcma input samples +generating 160 pcma input samples +got 4 l16 output frames (640 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 4 l16 output frames (640 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 4 l16 output frames (640 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 4 l16 output frames (640 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 4 l16 output frames (640 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 4 l16 output frames (640 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 4 l16 output frames (640 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 4 l16 output frames (640 octets) +== Transcoding test == +converting pcma -> pcma +generating 160 pcma input samples +generating 160 pcma input samples +got 4 pcma output frames (320 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 4 pcma output frames (320 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 4 pcma output frames (320 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 4 pcma output frames (320 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 4 pcma output frames (320 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 4 pcma output frames (320 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 4 pcma output frames (320 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 4 pcma output frames (320 octets) +== Transcoding test == +converting pcma -> l16 +generating 160 pcma input samples +generating 160 pcma input samples +got 3 l16 output frames (480 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 3 l16 output frames (480 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 3 l16 output frames (480 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 3 l16 output frames (480 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 3 l16 output frames (480 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 3 l16 output frames (480 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 3 l16 output frames (480 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 3 l16 output frames (480 octets) +== Transcoding test == +converting pcma -> pcma +generating 160 pcma input samples +generating 160 pcma input samples +got 3 pcma output frames (240 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 3 pcma output frames (240 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 3 pcma output frames (240 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 3 pcma output frames (240 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 3 pcma output frames (240 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 3 pcma output frames (240 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 3 pcma output frames (240 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 3 pcma output frames (240 octets) +== Transcoding test == +converting pcma -> l16 +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +== Transcoding test == +converting pcma -> pcma +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 4465b25..57310d6 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -27,6 +27,13 @@ cat $abs_srcdir/mgcp/mgcp_test.ok > expout AT_CHECK([$abs_top_builddir/tests/mgcp/mgcp_test], [], [expout], [ignore]) AT_CLEANUP +AT_SETUP([mgcp-trans]) +AT_KEYWORDS([mgcp-trans]) +AT_CHECK([test "$enable_mgcp_transcoding_test" == yes || exit 77]) +cat $abs_srcdir/mgcp/mgcp_transcoding_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/mgcp/mgcp_transcoding_test], [], [expout], [ignore]) +AT_CLEANUP + AT_SETUP([gprs]) AT_KEYWORDS([gprs]) cat $abs_srcdir/gprs/gprs_test.ok > expout -- 1.7.9.5 From jerlbeck at sysmocom.de Mon May 12 10:39:06 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Mon, 12 May 2014 12:39:06 +0200 Subject: [PATCH 10/11] mgcp: Move transcoding to libmgcp In-Reply-To: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1399891147-31419-10-git-send-email-jerlbeck@sysmocom.de> This patch moves the files relevant to transcoding from src/osmo-bsc_mgcp to src/libmgcp and src/include/openbsc. Makefiles and include directives are being updated accordingly. Sponsored-by: On-Waves ehf --- openbsc/contrib/testconv/Makefile | 3 +- openbsc/contrib/testconv/testconv_main.c | 2 +- openbsc/include/openbsc/Makefile.am | 3 +- openbsc/include/openbsc/mgcp_transcode.h | 36 ++ openbsc/src/libmgcp/Makefile.am | 12 +- openbsc/src/libmgcp/g711common.h | 187 ++++++++++ openbsc/src/libmgcp/mgcp_transcode.c | 553 ++++++++++++++++++++++++++++ openbsc/src/osmo-bsc_mgcp/Makefile.am | 9 +- openbsc/src/osmo-bsc_mgcp/g711common.h | 187 ---------- openbsc/src/osmo-bsc_mgcp/mgcp_main.c | 7 +- openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c | 553 ---------------------------- openbsc/src/osmo-bsc_mgcp/mgcp_transcode.h | 36 -- openbsc/tests/mgcp/Makefile.am | 2 +- openbsc/tests/mgcp/mgcp_transcoding_test.c | 2 +- 14 files changed, 795 insertions(+), 797 deletions(-) create mode 100644 openbsc/include/openbsc/mgcp_transcode.h create mode 100644 openbsc/src/libmgcp/g711common.h create mode 100644 openbsc/src/libmgcp/mgcp_transcode.c delete mode 100644 openbsc/src/osmo-bsc_mgcp/g711common.h delete mode 100644 openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c delete mode 100644 openbsc/src/osmo-bsc_mgcp/mgcp_transcode.h diff --git a/openbsc/contrib/testconv/Makefile b/openbsc/contrib/testconv/Makefile index 90adecc..bb856f7 100644 --- a/openbsc/contrib/testconv/Makefile +++ b/openbsc/contrib/testconv/Makefile @@ -1,5 +1,5 @@ -OBJS = testconv_main.o mgcp_transcode.o +OBJS = testconv_main.o CC = gcc CFLAGS = -O0 -ggdb -Wall @@ -11,7 +11,6 @@ testconv: $(OBJS) $(CC) -o $@ $^ $(LDFLAGS) $(LIBS) testconv_main.o: testconv_main.c -mgcp_transcode.o: ../../src/osmo-bsc_mgcp/mgcp_transcode.c $(OBJS): $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< diff --git a/openbsc/contrib/testconv/testconv_main.c b/openbsc/contrib/testconv/testconv_main.c index e74c686..89dce1a 100644 --- a/openbsc/contrib/testconv/testconv_main.c +++ b/openbsc/contrib/testconv/testconv_main.c @@ -17,7 +17,7 @@ #error "Requires MGCP transcoding enabled (see --enable-mgcp-transcoding)" #endif -#include "src/osmo-bsc_mgcp/mgcp_transcode.h" +#include "openbsc/mgcp_transcode.h" static int audio_name_to_type(const char *name) { diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 8f7c1c4..6b08d07 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -13,7 +13,8 @@ noinst_HEADERS = abis_nm.h abis_rsl.h db.h gsm_04_08.h gsm_data.h \ osmo_bsc_rf.h osmo_bsc.h network_listen.h bsc_nat_sccp.h \ osmo_msc_data.h osmo_bsc_grace.h sms_queue.h abis_om2000.h \ bss.h gsm_data_shared.h control_cmd.h ipaccess.h mncc_int.h \ - arfcn_range_encode.h nat_rewrite_trie.h bsc_nat_callstats.h + arfcn_range_encode.h nat_rewrite_trie.h bsc_nat_callstats.h \ + mgcp_transcode.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/mgcp_transcode.h b/openbsc/include/openbsc/mgcp_transcode.h new file mode 100644 index 0000000..0961634 --- /dev/null +++ b/openbsc/include/openbsc/mgcp_transcode.h @@ -0,0 +1,36 @@ +/* + * (C) 2014 by On-Waves + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +#ifndef OPENBSC_MGCP_TRANSCODE_H +#define OPENBSC_MGCP_TRANSCODE_H + +int mgcp_transcoding_setup(struct mgcp_endpoint *endp, + struct mgcp_rtp_end *dst_end, + struct mgcp_rtp_end *src_end); + +void mgcp_transcoding_net_downlink_format(struct mgcp_endpoint *endp, + int *payload_type, + const char**audio_name, + const char**fmtp_extra); + +int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp, + struct mgcp_rtp_end *dst_end, + char *data, int *len, int buf_size); + +int mgcp_transcoding_get_frame_size(void *state_, int nsamples, int dst); +#endif /* OPENBSC_MGCP_TRANSCODE_H */ diff --git a/openbsc/src/libmgcp/Makefile.am b/openbsc/src/libmgcp/Makefile.am index 72f625d..bd02e61 100644 --- a/openbsc/src/libmgcp/Makefile.am +++ b/openbsc/src/libmgcp/Makefile.am @@ -1,7 +1,15 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) -AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS) -AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(COVERAGE_LDFLAGS) +AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS) \ + $(LIBBCG729_CFLAGS) +AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(COVERAGE_LDFLAGS) \ + $(LIBBCG729_LIBS) noinst_LIBRARIES = libmgcp.a +noinst_HEADERS = g711common.h + libmgcp_a_SOURCES = mgcp_protocol.c mgcp_network.c mgcp_vty.c + +if BUILD_MGCP_TRANSCODING + libmgcp_a_SOURCES += mgcp_transcode.c +endif diff --git a/openbsc/src/libmgcp/g711common.h b/openbsc/src/libmgcp/g711common.h new file mode 100644 index 0000000..cb35fc6 --- /dev/null +++ b/openbsc/src/libmgcp/g711common.h @@ -0,0 +1,187 @@ +/* + * PCM - A-Law conversion + * Copyright (c) 2000 by Abramo Bagnara + * + * Wrapper for linphone Codec class by Simon Morlat + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +static inline int val_seg(int val) +{ + int r = 0; + val >>= 7; /*7 = 4 + 3*/ + if (val & 0xf0) { + val >>= 4; + r += 4; + } + if (val & 0x0c) { + val >>= 2; + r += 2; + } + if (val & 0x02) + r += 1; + return r; +} + +/* + * s16_to_alaw() - Convert a 16-bit linear PCM value to 8-bit A-law + * + * s16_to_alaw() accepts an 16-bit integer and encodes it as A-law data. + * + * Linear Input Code Compressed Code + * ------------------------ --------------- + * 0000000wxyza 000wxyz + * 0000001wxyza 001wxyz + * 000001wxyzab 010wxyz + * 00001wxyzabc 011wxyz + * 0001wxyzabcd 100wxyz + * 001wxyzabcde 101wxyz + * 01wxyzabcdef 110wxyz + * 1wxyzabcdefg 111wxyz + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + * G711 is designed for 13 bits input signal, this function add extra shifting to take this into account. + */ + +static inline unsigned char s16_to_alaw(int pcm_val) +{ + int mask; + int seg; + unsigned char aval; + + if (pcm_val >= 0) { + mask = 0xD5; + } else { + mask = 0x55; + pcm_val = -pcm_val; + if (pcm_val > 0x7fff) + pcm_val = 0x7fff; + } + + if (pcm_val < 256) /*256 = 32 << 3*/ + aval = pcm_val >> 4; /*4 = 1 + 3*/ + else { + /* Convert the scaled magnitude to segment number. */ + seg = val_seg(pcm_val); + aval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f); + } + return aval ^ mask; +} + +/* + * alaw_to_s16() - Convert an A-law value to 16-bit linear PCM + * + */ +static inline int alaw_to_s16(unsigned char a_val) +{ + int t; + int seg; + + a_val ^= 0x55; + t = a_val & 0x7f; + if (t < 16) + t = (t << 4) + 8; + else { + seg = (t >> 4) & 0x07; + t = ((t & 0x0f) << 4) + 0x108; + t <<= seg -1; + } + return ((a_val & 0x80) ? t : -t); +} +/* + * s16_to_ulaw() - Convert a linear PCM value to u-law + * + * In order to simplify the encoding process, the original linear magnitude + * is biased by adding 33 which shifts the encoding range from (0 - 8158) to + * (33 - 8191). The result can be seen in the following encoding table: + * + * Biased Linear Input Code Compressed Code + * ------------------------ --------------- + * 00000001wxyza 000wxyz + * 0000001wxyzab 001wxyz + * 000001wxyzabc 010wxyz + * 00001wxyzabcd 011wxyz + * 0001wxyzabcde 100wxyz + * 001wxyzabcdef 101wxyz + * 01wxyzabcdefg 110wxyz + * 1wxyzabcdefgh 111wxyz + * + * Each biased linear code has a leading 1 which identifies the segment + * number. The value of the segment number is equal to 7 minus the number + * of leading 0's. The quantization interval is directly available as the + * four bits wxyz. * The trailing bits (a - h) are ignored. + * + * Ordinarily the complement of the resulting code word is used for + * transmission, and so the code word is complemented before it is returned. + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ + +static inline unsigned char s16_to_ulaw(int pcm_val) /* 2's complement (16-bit range) */ +{ + int mask; + int seg; + unsigned char uval; + + if (pcm_val < 0) { + pcm_val = 0x84 - pcm_val; + mask = 0x7f; + } else { + pcm_val += 0x84; + mask = 0xff; + } + if (pcm_val > 0x7fff) + pcm_val = 0x7fff; + + /* Convert the scaled magnitude to segment number. */ + seg = val_seg(pcm_val); + + /* + * Combine the sign, segment, quantization bits; + * and complement the code word. + */ + uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f); + return uval ^ mask; +} + +/* + * ulaw_to_s16() - Convert a u-law value to 16-bit linear PCM + * + * First, a biased linear code is derived from the code word. An unbiased + * output can then be obtained by subtracting 33 from the biased code. + * + * Note that this function expects to be passed the complement of the + * original code word. This is in keeping with ISDN conventions. + */ +static inline int ulaw_to_s16(unsigned char u_val) +{ + int t; + + /* Complement to obtain normal u-law value. */ + u_val = ~u_val; + + /* + * Extract and bias the quantization bits. Then + * shift up by the segment number and subtract out the bias. + */ + t = ((u_val & 0x0f) << 3) + 0x84; + t <<= (u_val & 0x70) >> 4; + + return ((u_val & 0x80) ? (0x84 - t) : (t - 0x84)); +} diff --git a/openbsc/src/libmgcp/mgcp_transcode.c b/openbsc/src/libmgcp/mgcp_transcode.c new file mode 100644 index 0000000..edd3178 --- /dev/null +++ b/openbsc/src/libmgcp/mgcp_transcode.c @@ -0,0 +1,553 @@ +/* + * (C) 2014 by On-Waves + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include + + +#include "../../bscconfig.h" + +#include "g711common.h" +#include +#ifdef HAVE_BCG729 +#include +#include +#endif + +#include +#include +#include + +#include + +enum audio_format { + AF_INVALID, + AF_S16, + AF_L16, + AF_GSM, + AF_G729, + AF_PCMA +}; + +struct mgcp_process_rtp_state { + /* decoding */ + enum audio_format src_fmt; + union { + gsm gsm_handle; +#ifdef HAVE_BCG729 + bcg729DecoderChannelContextStruct *g729_dec; +#endif + } src; + size_t src_frame_size; + size_t src_samples_per_frame; + + /* processing */ + + /* encoding */ + enum audio_format dst_fmt; + union { + gsm gsm_handle; +#ifdef HAVE_BCG729 + bcg729EncoderChannelContextStruct *g729_enc; +#endif + } dst; + size_t dst_frame_size; + size_t dst_samples_per_frame; + int dst_packet_duration; + + int is_running; + uint16_t next_seq; + uint32_t next_time; + int16_t samples[10*160]; + size_t sample_cnt; + size_t sample_offs; +}; + +int mgcp_transcoding_get_frame_size(void *state_, int nsamples, int dst) +{ + struct mgcp_process_rtp_state *state = state_; + if (dst) + return (nsamples >= 0 ? + nsamples / state->dst_samples_per_frame : + 1) * state->dst_frame_size; + else + return (nsamples >= 0 ? + nsamples / state->src_samples_per_frame : + 1) * state->src_frame_size; +} + +static enum audio_format get_audio_format(const struct mgcp_rtp_end *rtp_end) +{ + if (rtp_end->subtype_name) { + if (!strcmp("GSM", rtp_end->subtype_name)) + return AF_GSM; + if (!strcmp("PCMA", rtp_end->subtype_name)) + return AF_PCMA; +#ifdef HAVE_BCG729 + if (!strcmp("G729", rtp_end->subtype_name)) + return AF_G729; +#endif + if (!strcmp("L16", rtp_end->subtype_name)) + return AF_L16; + } + + switch (rtp_end->payload_type) { + case 3 /* GSM */: + return AF_GSM; + case 8 /* PCMA */: + return AF_PCMA; +#ifdef HAVE_BCG729 + case 18 /* G.729 */: + return AF_G729; +#endif + case 11 /* L16 */: + return AF_L16; + default: + return AF_INVALID; + } +} + +static void l16_encode(short *sample, unsigned char *buf, size_t n) +{ + for (; n > 0; --n, ++sample, buf += 2) { + buf[0] = sample[0] >> 8; + buf[1] = sample[0] & 0xff; + } +} + +static void l16_decode(unsigned char *buf, short *sample, size_t n) +{ + for (; n > 0; --n, ++sample, buf += 2) + sample[0] = ((short)buf[0] << 8) | buf[1]; +} + +static void alaw_encode(short *sample, unsigned char *buf, size_t n) +{ + for (; n > 0; --n) + *(buf++) = s16_to_alaw(*(sample++)); +} + +static void alaw_decode(unsigned char *buf, short *sample, size_t n) +{ + for (; n > 0; --n) + *(sample++) = alaw_to_s16(*(buf++)); +} + +static int processing_state_destructor(struct mgcp_process_rtp_state *state) +{ + switch (state->src_fmt) { + case AF_GSM: + if (state->dst.gsm_handle) + gsm_destroy(state->src.gsm_handle); + break; +#ifdef HAVE_BCG729 + case AF_G729: + if (state->src.g729_dec) + closeBcg729DecoderChannel(state->src.g729_dec); + break; +#endif + default: + break; + } + switch (state->dst_fmt) { + case AF_GSM: + if (state->dst.gsm_handle) + gsm_destroy(state->dst.gsm_handle); + break; +#ifdef HAVE_BCG729 + case AF_G729: + if (state->dst.g729_enc) + closeBcg729EncoderChannel(state->dst.g729_enc); + break; +#endif + default: + break; + } + return 0; +} + +int mgcp_transcoding_setup(struct mgcp_endpoint *endp, + struct mgcp_rtp_end *dst_end, + struct mgcp_rtp_end *src_end) +{ + struct mgcp_process_rtp_state *state = dst_end->rtp_process_data; + enum audio_format src_fmt, dst_fmt; + + /* cleanup first */ + if (state) { + talloc_free(state); + dst_end->rtp_process_data = NULL; + } + + if (!src_end) + return 0; + + src_fmt = get_audio_format(src_end); + dst_fmt = get_audio_format(dst_end); + + LOGP(DMGCP, LOGL_ERROR, + "Checking transcoding: %s (%d) -> %s (%d)\n", + src_end->subtype_name, src_end->payload_type, + dst_end->subtype_name, dst_end->payload_type); + + if (src_fmt == AF_INVALID || dst_fmt == AF_INVALID) { + if (!src_end->subtype_name || !dst_end->subtype_name) + /* Not enough info, do nothing */ + return 0; + + if (strcmp(src_end->subtype_name, dst_end->subtype_name) == 0) + /* Nothing to do */ + return 0; + + LOGP(DMGCP, LOGL_ERROR, + "Cannot transcode: %s codec not supported (%s -> %s).\n", + src_fmt != AF_INVALID ? "destination" : "source", + src_end->audio_name, dst_end->audio_name); + return -EINVAL; + } + + if (src_end->rate && dst_end->rate && src_end->rate != dst_end->rate) { + LOGP(DMGCP, LOGL_ERROR, + "Cannot transcode: rate conversion (%d -> %d) not supported.\n", + src_end->rate, dst_end->rate); + return -EINVAL; + } + + state = talloc_zero(endp->tcfg->cfg, struct mgcp_process_rtp_state); + talloc_set_destructor(state, processing_state_destructor); + dst_end->rtp_process_data = state; + + state->src_fmt = src_fmt; + + switch (state->src_fmt) { + case AF_L16: + case AF_S16: + state->src_frame_size = 80 * sizeof(short); + state->src_samples_per_frame = 80; + break; + case AF_GSM: + state->src_frame_size = sizeof(gsm_frame); + state->src_samples_per_frame = 160; + state->src.gsm_handle = gsm_create(); + if (!state->src.gsm_handle) { + LOGP(DMGCP, LOGL_ERROR, + "Failed to initialize GSM decoder.\n"); + return -EINVAL; + } + break; +#ifdef HAVE_BCG729 + case AF_G729: + state->src_frame_size = 10; + state->src_samples_per_frame = 80; + state->src.g729_dec = initBcg729DecoderChannel(); + if (!state->src.g729_dec) { + LOGP(DMGCP, LOGL_ERROR, + "Failed to initialize G.729 decoder.\n"); + return -EINVAL; + } + break; +#endif + case AF_PCMA: + state->src_frame_size = 80; + state->src_samples_per_frame = 80; + break; + default: + break; + } + + state->dst_fmt = dst_fmt; + + switch (state->dst_fmt) { + case AF_L16: + case AF_S16: + state->dst_frame_size = 80*sizeof(short); + state->dst_samples_per_frame = 80; + break; + case AF_GSM: + state->dst_frame_size = sizeof(gsm_frame); + state->dst_samples_per_frame = 160; + state->dst.gsm_handle = gsm_create(); + if (!state->dst.gsm_handle) { + LOGP(DMGCP, LOGL_ERROR, + "Failed to initialize GSM encoder.\n"); + return -EINVAL; + } + break; +#ifdef HAVE_BCG729 + case AF_G729: + state->dst_frame_size = 10; + state->dst_samples_per_frame = 80; + state->dst.g729_enc = initBcg729EncoderChannel(); + if (!state->dst.g729_enc) { + LOGP(DMGCP, LOGL_ERROR, + "Failed to initialize G.729 decoder.\n"); + return -EINVAL; + } + break; +#endif + case AF_PCMA: + state->dst_frame_size = 80; + state->dst_samples_per_frame = 80; + break; + default: + break; + } + + if (dst_end->force_output_ptime) + state->dst_packet_duration = mgcp_rtp_packet_duration(endp, dst_end); + + LOGP(DMGCP, LOGL_INFO, + "Initialized RTP processing on: 0x%x " + "conv: %d (%d, %d, %s) -> %d (%d, %d, %s)\n", + ENDPOINT_NUMBER(endp), + src_fmt, src_end->payload_type, src_end->rate, src_end->fmtp_extra, + dst_fmt, dst_end->payload_type, dst_end->rate, dst_end->fmtp_extra); + + return 0; +} + +void mgcp_transcoding_net_downlink_format(struct mgcp_endpoint *endp, + int *payload_type, + const char**audio_name, + const char**fmtp_extra) +{ + struct mgcp_process_rtp_state *state = endp->net_end.rtp_process_data; + if (!state || endp->net_end.payload_type < 0) { + *payload_type = endp->bts_end.payload_type; + *audio_name = endp->bts_end.audio_name; + *fmtp_extra = endp->bts_end.fmtp_extra; + return; + } + + *payload_type = endp->net_end.payload_type; + *fmtp_extra = endp->net_end.fmtp_extra; + *audio_name = endp->net_end.audio_name; +} + +static int decode_audio(struct mgcp_process_rtp_state *state, + uint8_t **src, size_t *nbytes) +{ + while (*nbytes >= state->src_frame_size) { + if (state->sample_cnt + state->src_samples_per_frame > ARRAY_SIZE(state->samples)) { + LOGP(DMGCP, LOGL_ERROR, + "Sample buffer too small: %d > %d.\n", + state->sample_cnt + state->src_samples_per_frame, + ARRAY_SIZE(state->samples)); + return -ENOSPC; + } + switch (state->src_fmt) { + case AF_GSM: + if (gsm_decode(state->src.gsm_handle, + (gsm_byte *)*src, state->samples + state->sample_cnt) < 0) { + LOGP(DMGCP, LOGL_ERROR, + "Failed to decode GSM.\n"); + return -EINVAL; + } + break; +#ifdef HAVE_BCG729 + case AF_G729: + bcg729Decoder(state->src.g729_dec, *src, 0, state->samples + state->sample_cnt); + break; +#endif + case AF_PCMA: + alaw_decode(*src, state->samples + state->sample_cnt, + state->src_samples_per_frame); + break; + case AF_S16: + memmove(state->samples + state->sample_cnt, *src, + state->src_frame_size); + break; + case AF_L16: + l16_decode(*src, state->samples + state->sample_cnt, + state->src_samples_per_frame); + break; + default: + break; + } + *src += state->src_frame_size; + *nbytes -= state->src_frame_size; + state->sample_cnt += state->src_samples_per_frame; + } + return 0; +} + +static int encode_audio(struct mgcp_process_rtp_state *state, + uint8_t *dst, size_t buf_size, size_t max_samples) +{ + int nbytes = 0; + size_t nsamples = 0; + /* Encode samples into dst */ + while (nsamples + state->dst_samples_per_frame <= max_samples) { + if (nbytes + state->dst_frame_size > buf_size) { + if (nbytes > 0) + break; + + /* Not even one frame fits into the buffer */ + LOGP(DMGCP, LOGL_INFO, + "Encoding (RTP) buffer too small: %d > %d.\n", + nbytes + state->dst_frame_size, buf_size); + return -ENOSPC; + } + switch (state->dst_fmt) { + case AF_GSM: + gsm_encode(state->dst.gsm_handle, + state->samples + state->sample_offs, dst); + break; +#ifdef HAVE_BCG729 + case AF_G729: + bcg729Encoder(state->dst.g729_enc, + state->samples + state->sample_offs, dst); + break; +#endif + case AF_PCMA: + alaw_encode(state->samples + state->sample_offs, dst, + state->src_samples_per_frame); + break; + case AF_S16: + memmove(dst, state->samples + state->sample_offs, + state->dst_frame_size); + break; + case AF_L16: + l16_encode(state->samples + state->sample_offs, dst, + state->src_samples_per_frame); + break; + default: + break; + } + dst += state->dst_frame_size; + nbytes += state->dst_frame_size; + state->sample_offs += state->dst_samples_per_frame; + nsamples += state->dst_samples_per_frame; + } + state->sample_cnt -= nsamples; + return nbytes; +} + +int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp, + struct mgcp_rtp_end *dst_end, + char *data, int *len, int buf_size) +{ + struct mgcp_process_rtp_state *state = dst_end->rtp_process_data; + size_t rtp_hdr_size = 12; + char *payload_data = data + rtp_hdr_size; + int payload_len = *len - rtp_hdr_size; + // size_t sample_idx; + uint8_t *src = (uint8_t *)payload_data; + uint8_t *dst = (uint8_t *)payload_data; + size_t nbytes = payload_len; + // size_t frame_remainder; + size_t nsamples; + size_t max_samples; + uint32_t ts_no; + int rc; + + if (!state) + return 0; + + if (state->src_fmt == state->dst_fmt) { + if (!state->dst_packet_duration) + return 0; + + /* TODO: repackage without transcoding */ + } + + /* If the remaining samples do not fit into a fixed ptime, + * a) discard them, if the next packet is much later + * b) add silence and * send it, if the current packet is not + * yet too late + * c) append the sample data, if the timestamp matches exactly + */ + + /* TODO: check payload type (-> G.711 comfort noise) */ + + if (payload_len > 0) { + ts_no = ntohl(*(uint32_t*)(data+4)); + if (!state->is_running) + state->next_seq = ntohs(*(uint32_t*)(data+4)); + + state->is_running = 1; + + if (state->sample_cnt > 0) { + int32_t delta = ts_no - state->next_time; + /* TODO: check sequence? reordering? packet loss? */ + + if (delta > state->sample_cnt) + /* There is a time gap between the last packet + * and the current one. Just discard the + * partial data that is left in the buffer. + * TODO: This can be improved by adding silence + * instead if the delta is small enough. + */ + state->sample_cnt = 0; + else if (delta < 0) { + LOGP(DMGCP, LOGL_NOTICE, + "RTP time jumps backwards, delta = %d, " + "discarding buffered samples\n", + delta); + state->sample_cnt = 0; + state->sample_offs = 0; + return -EAGAIN; + } + + /* Make sure the samples start without offset */ + fprintf(stderr, "Moving %d samples to buffer start (offset %d)\n", state->sample_cnt, state->sample_offs); + if (state->sample_offs && state->sample_cnt) + memmove(&state->samples[0], + &state->samples[state->sample_offs], + state->sample_cnt * sizeof(state->samples[0])); + } + + state->sample_offs = 0; + + /* Append decoded audio to samples */ + decode_audio(state, &src, &nbytes); + + if (nbytes > 0) + LOGP(DMGCP, LOGL_NOTICE, + "Skipped audio frame in RTP packet: %d octets\n", + nbytes); + } else + ts_no = state->next_time; + + if (state->sample_cnt < state->dst_packet_duration) + return -EAGAIN; + + max_samples = + state->dst_packet_duration ? + state->dst_packet_duration : state->sample_cnt; + + nsamples = state->sample_cnt; + + rc = encode_audio(state, dst, buf_size, max_samples); + if (rc <= 0) + return rc; + + nsamples -= state->sample_cnt; + fprintf(stderr, "Wrote %d samples to buffer (offset %d)\n", nsamples, state->sample_offs); + + *len = rtp_hdr_size + rc; + *(uint16_t*)(data+2) = htonl(state->next_seq); + *(uint32_t*)(data+4) = htonl(ts_no); + + state->next_seq += 1; + state->next_time = ts_no + nsamples; + + return nsamples ? rtp_hdr_size : 0; +} diff --git a/openbsc/src/osmo-bsc_mgcp/Makefile.am b/openbsc/src/osmo-bsc_mgcp/Makefile.am index a620e7a..da02380 100644 --- a/openbsc/src/osmo-bsc_mgcp/Makefile.am +++ b/openbsc/src/osmo-bsc_mgcp/Makefile.am @@ -1,16 +1,11 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) \ - $(LIBOSMOVTY_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) \ - $(LIBBCG729_CFLAGS) + $(LIBOSMOVTY_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) bin_PROGRAMS = osmo-bsc_mgcp osmo_bsc_mgcp_SOURCES = mgcp_main.c -if BUILD_MGCP_TRANSCODING - osmo_bsc_mgcp_SOURCES += mgcp_transcode.c -endif + osmo_bsc_mgcp_LDADD = $(top_builddir)/src/libcommon/libcommon.a \ $(top_builddir)/src/libmgcp/libmgcp.a -lrt \ $(LIBOSMOVTY_LIBS) $(LIBOSMOCORE_LIBS) $(LIBBCG729_LIBS) - -noinst_HEADERS = g711common.h mgcp_transcode.h diff --git a/openbsc/src/osmo-bsc_mgcp/g711common.h b/openbsc/src/osmo-bsc_mgcp/g711common.h deleted file mode 100644 index cb35fc6..0000000 --- a/openbsc/src/osmo-bsc_mgcp/g711common.h +++ /dev/null @@ -1,187 +0,0 @@ -/* - * PCM - A-Law conversion - * Copyright (c) 2000 by Abramo Bagnara - * - * Wrapper for linphone Codec class by Simon Morlat - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -static inline int val_seg(int val) -{ - int r = 0; - val >>= 7; /*7 = 4 + 3*/ - if (val & 0xf0) { - val >>= 4; - r += 4; - } - if (val & 0x0c) { - val >>= 2; - r += 2; - } - if (val & 0x02) - r += 1; - return r; -} - -/* - * s16_to_alaw() - Convert a 16-bit linear PCM value to 8-bit A-law - * - * s16_to_alaw() accepts an 16-bit integer and encodes it as A-law data. - * - * Linear Input Code Compressed Code - * ------------------------ --------------- - * 0000000wxyza 000wxyz - * 0000001wxyza 001wxyz - * 000001wxyzab 010wxyz - * 00001wxyzabc 011wxyz - * 0001wxyzabcd 100wxyz - * 001wxyzabcde 101wxyz - * 01wxyzabcdef 110wxyz - * 1wxyzabcdefg 111wxyz - * - * For further information see John C. Bellamy's Digital Telephony, 1982, - * John Wiley & Sons, pps 98-111 and 472-476. - * G711 is designed for 13 bits input signal, this function add extra shifting to take this into account. - */ - -static inline unsigned char s16_to_alaw(int pcm_val) -{ - int mask; - int seg; - unsigned char aval; - - if (pcm_val >= 0) { - mask = 0xD5; - } else { - mask = 0x55; - pcm_val = -pcm_val; - if (pcm_val > 0x7fff) - pcm_val = 0x7fff; - } - - if (pcm_val < 256) /*256 = 32 << 3*/ - aval = pcm_val >> 4; /*4 = 1 + 3*/ - else { - /* Convert the scaled magnitude to segment number. */ - seg = val_seg(pcm_val); - aval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f); - } - return aval ^ mask; -} - -/* - * alaw_to_s16() - Convert an A-law value to 16-bit linear PCM - * - */ -static inline int alaw_to_s16(unsigned char a_val) -{ - int t; - int seg; - - a_val ^= 0x55; - t = a_val & 0x7f; - if (t < 16) - t = (t << 4) + 8; - else { - seg = (t >> 4) & 0x07; - t = ((t & 0x0f) << 4) + 0x108; - t <<= seg -1; - } - return ((a_val & 0x80) ? t : -t); -} -/* - * s16_to_ulaw() - Convert a linear PCM value to u-law - * - * In order to simplify the encoding process, the original linear magnitude - * is biased by adding 33 which shifts the encoding range from (0 - 8158) to - * (33 - 8191). The result can be seen in the following encoding table: - * - * Biased Linear Input Code Compressed Code - * ------------------------ --------------- - * 00000001wxyza 000wxyz - * 0000001wxyzab 001wxyz - * 000001wxyzabc 010wxyz - * 00001wxyzabcd 011wxyz - * 0001wxyzabcde 100wxyz - * 001wxyzabcdef 101wxyz - * 01wxyzabcdefg 110wxyz - * 1wxyzabcdefgh 111wxyz - * - * Each biased linear code has a leading 1 which identifies the segment - * number. The value of the segment number is equal to 7 minus the number - * of leading 0's. The quantization interval is directly available as the - * four bits wxyz. * The trailing bits (a - h) are ignored. - * - * Ordinarily the complement of the resulting code word is used for - * transmission, and so the code word is complemented before it is returned. - * - * For further information see John C. Bellamy's Digital Telephony, 1982, - * John Wiley & Sons, pps 98-111 and 472-476. - */ - -static inline unsigned char s16_to_ulaw(int pcm_val) /* 2's complement (16-bit range) */ -{ - int mask; - int seg; - unsigned char uval; - - if (pcm_val < 0) { - pcm_val = 0x84 - pcm_val; - mask = 0x7f; - } else { - pcm_val += 0x84; - mask = 0xff; - } - if (pcm_val > 0x7fff) - pcm_val = 0x7fff; - - /* Convert the scaled magnitude to segment number. */ - seg = val_seg(pcm_val); - - /* - * Combine the sign, segment, quantization bits; - * and complement the code word. - */ - uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f); - return uval ^ mask; -} - -/* - * ulaw_to_s16() - Convert a u-law value to 16-bit linear PCM - * - * First, a biased linear code is derived from the code word. An unbiased - * output can then be obtained by subtracting 33 from the biased code. - * - * Note that this function expects to be passed the complement of the - * original code word. This is in keeping with ISDN conventions. - */ -static inline int ulaw_to_s16(unsigned char u_val) -{ - int t; - - /* Complement to obtain normal u-law value. */ - u_val = ~u_val; - - /* - * Extract and bias the quantization bits. Then - * shift up by the segment number and subtract out the bias. - */ - t = ((u_val & 0x0f) << 3) + 0x84; - t <<= (u_val & 0x70) >> 4; - - return ((u_val & 0x80) ? (0x84 - t) : (t - 0x84)); -} diff --git a/openbsc/src/osmo-bsc_mgcp/mgcp_main.c b/openbsc/src/osmo-bsc_mgcp/mgcp_main.c index 5ac4c26..8c3808a 100644 --- a/openbsc/src/osmo-bsc_mgcp/mgcp_main.c +++ b/openbsc/src/osmo-bsc_mgcp/mgcp_main.c @@ -31,11 +31,6 @@ #include -#include "g711common.h" -#include -#include -#include - #include #include #include @@ -55,7 +50,7 @@ #include "../../bscconfig.h" #ifdef BUILD_MGCP_TRANSCODING -#include "mgcp_transcode.h" +#include "openbsc/mgcp_transcode.h" #endif /* this is here for the vty... it will never be called */ diff --git a/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c b/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c deleted file mode 100644 index edd3178..0000000 --- a/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c +++ /dev/null @@ -1,553 +0,0 @@ -/* - * (C) 2014 by On-Waves - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -#include -#include -#include - - -#include "../../bscconfig.h" - -#include "g711common.h" -#include -#ifdef HAVE_BCG729 -#include -#include -#endif - -#include -#include -#include - -#include - -enum audio_format { - AF_INVALID, - AF_S16, - AF_L16, - AF_GSM, - AF_G729, - AF_PCMA -}; - -struct mgcp_process_rtp_state { - /* decoding */ - enum audio_format src_fmt; - union { - gsm gsm_handle; -#ifdef HAVE_BCG729 - bcg729DecoderChannelContextStruct *g729_dec; -#endif - } src; - size_t src_frame_size; - size_t src_samples_per_frame; - - /* processing */ - - /* encoding */ - enum audio_format dst_fmt; - union { - gsm gsm_handle; -#ifdef HAVE_BCG729 - bcg729EncoderChannelContextStruct *g729_enc; -#endif - } dst; - size_t dst_frame_size; - size_t dst_samples_per_frame; - int dst_packet_duration; - - int is_running; - uint16_t next_seq; - uint32_t next_time; - int16_t samples[10*160]; - size_t sample_cnt; - size_t sample_offs; -}; - -int mgcp_transcoding_get_frame_size(void *state_, int nsamples, int dst) -{ - struct mgcp_process_rtp_state *state = state_; - if (dst) - return (nsamples >= 0 ? - nsamples / state->dst_samples_per_frame : - 1) * state->dst_frame_size; - else - return (nsamples >= 0 ? - nsamples / state->src_samples_per_frame : - 1) * state->src_frame_size; -} - -static enum audio_format get_audio_format(const struct mgcp_rtp_end *rtp_end) -{ - if (rtp_end->subtype_name) { - if (!strcmp("GSM", rtp_end->subtype_name)) - return AF_GSM; - if (!strcmp("PCMA", rtp_end->subtype_name)) - return AF_PCMA; -#ifdef HAVE_BCG729 - if (!strcmp("G729", rtp_end->subtype_name)) - return AF_G729; -#endif - if (!strcmp("L16", rtp_end->subtype_name)) - return AF_L16; - } - - switch (rtp_end->payload_type) { - case 3 /* GSM */: - return AF_GSM; - case 8 /* PCMA */: - return AF_PCMA; -#ifdef HAVE_BCG729 - case 18 /* G.729 */: - return AF_G729; -#endif - case 11 /* L16 */: - return AF_L16; - default: - return AF_INVALID; - } -} - -static void l16_encode(short *sample, unsigned char *buf, size_t n) -{ - for (; n > 0; --n, ++sample, buf += 2) { - buf[0] = sample[0] >> 8; - buf[1] = sample[0] & 0xff; - } -} - -static void l16_decode(unsigned char *buf, short *sample, size_t n) -{ - for (; n > 0; --n, ++sample, buf += 2) - sample[0] = ((short)buf[0] << 8) | buf[1]; -} - -static void alaw_encode(short *sample, unsigned char *buf, size_t n) -{ - for (; n > 0; --n) - *(buf++) = s16_to_alaw(*(sample++)); -} - -static void alaw_decode(unsigned char *buf, short *sample, size_t n) -{ - for (; n > 0; --n) - *(sample++) = alaw_to_s16(*(buf++)); -} - -static int processing_state_destructor(struct mgcp_process_rtp_state *state) -{ - switch (state->src_fmt) { - case AF_GSM: - if (state->dst.gsm_handle) - gsm_destroy(state->src.gsm_handle); - break; -#ifdef HAVE_BCG729 - case AF_G729: - if (state->src.g729_dec) - closeBcg729DecoderChannel(state->src.g729_dec); - break; -#endif - default: - break; - } - switch (state->dst_fmt) { - case AF_GSM: - if (state->dst.gsm_handle) - gsm_destroy(state->dst.gsm_handle); - break; -#ifdef HAVE_BCG729 - case AF_G729: - if (state->dst.g729_enc) - closeBcg729EncoderChannel(state->dst.g729_enc); - break; -#endif - default: - break; - } - return 0; -} - -int mgcp_transcoding_setup(struct mgcp_endpoint *endp, - struct mgcp_rtp_end *dst_end, - struct mgcp_rtp_end *src_end) -{ - struct mgcp_process_rtp_state *state = dst_end->rtp_process_data; - enum audio_format src_fmt, dst_fmt; - - /* cleanup first */ - if (state) { - talloc_free(state); - dst_end->rtp_process_data = NULL; - } - - if (!src_end) - return 0; - - src_fmt = get_audio_format(src_end); - dst_fmt = get_audio_format(dst_end); - - LOGP(DMGCP, LOGL_ERROR, - "Checking transcoding: %s (%d) -> %s (%d)\n", - src_end->subtype_name, src_end->payload_type, - dst_end->subtype_name, dst_end->payload_type); - - if (src_fmt == AF_INVALID || dst_fmt == AF_INVALID) { - if (!src_end->subtype_name || !dst_end->subtype_name) - /* Not enough info, do nothing */ - return 0; - - if (strcmp(src_end->subtype_name, dst_end->subtype_name) == 0) - /* Nothing to do */ - return 0; - - LOGP(DMGCP, LOGL_ERROR, - "Cannot transcode: %s codec not supported (%s -> %s).\n", - src_fmt != AF_INVALID ? "destination" : "source", - src_end->audio_name, dst_end->audio_name); - return -EINVAL; - } - - if (src_end->rate && dst_end->rate && src_end->rate != dst_end->rate) { - LOGP(DMGCP, LOGL_ERROR, - "Cannot transcode: rate conversion (%d -> %d) not supported.\n", - src_end->rate, dst_end->rate); - return -EINVAL; - } - - state = talloc_zero(endp->tcfg->cfg, struct mgcp_process_rtp_state); - talloc_set_destructor(state, processing_state_destructor); - dst_end->rtp_process_data = state; - - state->src_fmt = src_fmt; - - switch (state->src_fmt) { - case AF_L16: - case AF_S16: - state->src_frame_size = 80 * sizeof(short); - state->src_samples_per_frame = 80; - break; - case AF_GSM: - state->src_frame_size = sizeof(gsm_frame); - state->src_samples_per_frame = 160; - state->src.gsm_handle = gsm_create(); - if (!state->src.gsm_handle) { - LOGP(DMGCP, LOGL_ERROR, - "Failed to initialize GSM decoder.\n"); - return -EINVAL; - } - break; -#ifdef HAVE_BCG729 - case AF_G729: - state->src_frame_size = 10; - state->src_samples_per_frame = 80; - state->src.g729_dec = initBcg729DecoderChannel(); - if (!state->src.g729_dec) { - LOGP(DMGCP, LOGL_ERROR, - "Failed to initialize G.729 decoder.\n"); - return -EINVAL; - } - break; -#endif - case AF_PCMA: - state->src_frame_size = 80; - state->src_samples_per_frame = 80; - break; - default: - break; - } - - state->dst_fmt = dst_fmt; - - switch (state->dst_fmt) { - case AF_L16: - case AF_S16: - state->dst_frame_size = 80*sizeof(short); - state->dst_samples_per_frame = 80; - break; - case AF_GSM: - state->dst_frame_size = sizeof(gsm_frame); - state->dst_samples_per_frame = 160; - state->dst.gsm_handle = gsm_create(); - if (!state->dst.gsm_handle) { - LOGP(DMGCP, LOGL_ERROR, - "Failed to initialize GSM encoder.\n"); - return -EINVAL; - } - break; -#ifdef HAVE_BCG729 - case AF_G729: - state->dst_frame_size = 10; - state->dst_samples_per_frame = 80; - state->dst.g729_enc = initBcg729EncoderChannel(); - if (!state->dst.g729_enc) { - LOGP(DMGCP, LOGL_ERROR, - "Failed to initialize G.729 decoder.\n"); - return -EINVAL; - } - break; -#endif - case AF_PCMA: - state->dst_frame_size = 80; - state->dst_samples_per_frame = 80; - break; - default: - break; - } - - if (dst_end->force_output_ptime) - state->dst_packet_duration = mgcp_rtp_packet_duration(endp, dst_end); - - LOGP(DMGCP, LOGL_INFO, - "Initialized RTP processing on: 0x%x " - "conv: %d (%d, %d, %s) -> %d (%d, %d, %s)\n", - ENDPOINT_NUMBER(endp), - src_fmt, src_end->payload_type, src_end->rate, src_end->fmtp_extra, - dst_fmt, dst_end->payload_type, dst_end->rate, dst_end->fmtp_extra); - - return 0; -} - -void mgcp_transcoding_net_downlink_format(struct mgcp_endpoint *endp, - int *payload_type, - const char**audio_name, - const char**fmtp_extra) -{ - struct mgcp_process_rtp_state *state = endp->net_end.rtp_process_data; - if (!state || endp->net_end.payload_type < 0) { - *payload_type = endp->bts_end.payload_type; - *audio_name = endp->bts_end.audio_name; - *fmtp_extra = endp->bts_end.fmtp_extra; - return; - } - - *payload_type = endp->net_end.payload_type; - *fmtp_extra = endp->net_end.fmtp_extra; - *audio_name = endp->net_end.audio_name; -} - -static int decode_audio(struct mgcp_process_rtp_state *state, - uint8_t **src, size_t *nbytes) -{ - while (*nbytes >= state->src_frame_size) { - if (state->sample_cnt + state->src_samples_per_frame > ARRAY_SIZE(state->samples)) { - LOGP(DMGCP, LOGL_ERROR, - "Sample buffer too small: %d > %d.\n", - state->sample_cnt + state->src_samples_per_frame, - ARRAY_SIZE(state->samples)); - return -ENOSPC; - } - switch (state->src_fmt) { - case AF_GSM: - if (gsm_decode(state->src.gsm_handle, - (gsm_byte *)*src, state->samples + state->sample_cnt) < 0) { - LOGP(DMGCP, LOGL_ERROR, - "Failed to decode GSM.\n"); - return -EINVAL; - } - break; -#ifdef HAVE_BCG729 - case AF_G729: - bcg729Decoder(state->src.g729_dec, *src, 0, state->samples + state->sample_cnt); - break; -#endif - case AF_PCMA: - alaw_decode(*src, state->samples + state->sample_cnt, - state->src_samples_per_frame); - break; - case AF_S16: - memmove(state->samples + state->sample_cnt, *src, - state->src_frame_size); - break; - case AF_L16: - l16_decode(*src, state->samples + state->sample_cnt, - state->src_samples_per_frame); - break; - default: - break; - } - *src += state->src_frame_size; - *nbytes -= state->src_frame_size; - state->sample_cnt += state->src_samples_per_frame; - } - return 0; -} - -static int encode_audio(struct mgcp_process_rtp_state *state, - uint8_t *dst, size_t buf_size, size_t max_samples) -{ - int nbytes = 0; - size_t nsamples = 0; - /* Encode samples into dst */ - while (nsamples + state->dst_samples_per_frame <= max_samples) { - if (nbytes + state->dst_frame_size > buf_size) { - if (nbytes > 0) - break; - - /* Not even one frame fits into the buffer */ - LOGP(DMGCP, LOGL_INFO, - "Encoding (RTP) buffer too small: %d > %d.\n", - nbytes + state->dst_frame_size, buf_size); - return -ENOSPC; - } - switch (state->dst_fmt) { - case AF_GSM: - gsm_encode(state->dst.gsm_handle, - state->samples + state->sample_offs, dst); - break; -#ifdef HAVE_BCG729 - case AF_G729: - bcg729Encoder(state->dst.g729_enc, - state->samples + state->sample_offs, dst); - break; -#endif - case AF_PCMA: - alaw_encode(state->samples + state->sample_offs, dst, - state->src_samples_per_frame); - break; - case AF_S16: - memmove(dst, state->samples + state->sample_offs, - state->dst_frame_size); - break; - case AF_L16: - l16_encode(state->samples + state->sample_offs, dst, - state->src_samples_per_frame); - break; - default: - break; - } - dst += state->dst_frame_size; - nbytes += state->dst_frame_size; - state->sample_offs += state->dst_samples_per_frame; - nsamples += state->dst_samples_per_frame; - } - state->sample_cnt -= nsamples; - return nbytes; -} - -int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp, - struct mgcp_rtp_end *dst_end, - char *data, int *len, int buf_size) -{ - struct mgcp_process_rtp_state *state = dst_end->rtp_process_data; - size_t rtp_hdr_size = 12; - char *payload_data = data + rtp_hdr_size; - int payload_len = *len - rtp_hdr_size; - // size_t sample_idx; - uint8_t *src = (uint8_t *)payload_data; - uint8_t *dst = (uint8_t *)payload_data; - size_t nbytes = payload_len; - // size_t frame_remainder; - size_t nsamples; - size_t max_samples; - uint32_t ts_no; - int rc; - - if (!state) - return 0; - - if (state->src_fmt == state->dst_fmt) { - if (!state->dst_packet_duration) - return 0; - - /* TODO: repackage without transcoding */ - } - - /* If the remaining samples do not fit into a fixed ptime, - * a) discard them, if the next packet is much later - * b) add silence and * send it, if the current packet is not - * yet too late - * c) append the sample data, if the timestamp matches exactly - */ - - /* TODO: check payload type (-> G.711 comfort noise) */ - - if (payload_len > 0) { - ts_no = ntohl(*(uint32_t*)(data+4)); - if (!state->is_running) - state->next_seq = ntohs(*(uint32_t*)(data+4)); - - state->is_running = 1; - - if (state->sample_cnt > 0) { - int32_t delta = ts_no - state->next_time; - /* TODO: check sequence? reordering? packet loss? */ - - if (delta > state->sample_cnt) - /* There is a time gap between the last packet - * and the current one. Just discard the - * partial data that is left in the buffer. - * TODO: This can be improved by adding silence - * instead if the delta is small enough. - */ - state->sample_cnt = 0; - else if (delta < 0) { - LOGP(DMGCP, LOGL_NOTICE, - "RTP time jumps backwards, delta = %d, " - "discarding buffered samples\n", - delta); - state->sample_cnt = 0; - state->sample_offs = 0; - return -EAGAIN; - } - - /* Make sure the samples start without offset */ - fprintf(stderr, "Moving %d samples to buffer start (offset %d)\n", state->sample_cnt, state->sample_offs); - if (state->sample_offs && state->sample_cnt) - memmove(&state->samples[0], - &state->samples[state->sample_offs], - state->sample_cnt * sizeof(state->samples[0])); - } - - state->sample_offs = 0; - - /* Append decoded audio to samples */ - decode_audio(state, &src, &nbytes); - - if (nbytes > 0) - LOGP(DMGCP, LOGL_NOTICE, - "Skipped audio frame in RTP packet: %d octets\n", - nbytes); - } else - ts_no = state->next_time; - - if (state->sample_cnt < state->dst_packet_duration) - return -EAGAIN; - - max_samples = - state->dst_packet_duration ? - state->dst_packet_duration : state->sample_cnt; - - nsamples = state->sample_cnt; - - rc = encode_audio(state, dst, buf_size, max_samples); - if (rc <= 0) - return rc; - - nsamples -= state->sample_cnt; - fprintf(stderr, "Wrote %d samples to buffer (offset %d)\n", nsamples, state->sample_offs); - - *len = rtp_hdr_size + rc; - *(uint16_t*)(data+2) = htonl(state->next_seq); - *(uint32_t*)(data+4) = htonl(ts_no); - - state->next_seq += 1; - state->next_time = ts_no + nsamples; - - return nsamples ? rtp_hdr_size : 0; -} diff --git a/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.h b/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.h deleted file mode 100644 index 0961634..0000000 --- a/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * (C) 2014 by On-Waves - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ -#ifndef OPENBSC_MGCP_TRANSCODE_H -#define OPENBSC_MGCP_TRANSCODE_H - -int mgcp_transcoding_setup(struct mgcp_endpoint *endp, - struct mgcp_rtp_end *dst_end, - struct mgcp_rtp_end *src_end); - -void mgcp_transcoding_net_downlink_format(struct mgcp_endpoint *endp, - int *payload_type, - const char**audio_name, - const char**fmtp_extra); - -int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp, - struct mgcp_rtp_end *dst_end, - char *data, int *len, int buf_size); - -int mgcp_transcoding_get_frame_size(void *state_, int nsamples, int dst); -#endif /* OPENBSC_MGCP_TRANSCODE_H */ diff --git a/openbsc/tests/mgcp/Makefile.am b/openbsc/tests/mgcp/Makefile.am index 81f28ae..2bc2da6 100644 --- a/openbsc/tests/mgcp/Makefile.am +++ b/openbsc/tests/mgcp/Makefile.am @@ -18,7 +18,7 @@ mgcp_test_LDADD = $(top_builddir)/src/libbsc/libbsc.a \ $(LIBOSMOCORE_LIBS) -lrt -lm $(LIBOSMOSCCP_LIBS) $(LIBOSMOVTY_LIBS) \ $(LIBRARY_DL) -mgcp_transcoding_test_SOURCES = mgcp_transcoding_test.c $(top_builddir)/src/osmo-bsc_mgcp/mgcp_transcode.c +mgcp_transcoding_test_SOURCES = mgcp_transcoding_test.c mgcp_transcoding_test_LDADD = \ $(top_builddir)/src/libbsc/libbsc.a \ diff --git a/openbsc/tests/mgcp/mgcp_transcoding_test.c b/openbsc/tests/mgcp/mgcp_transcoding_test.c index a1af157..264dbe6 100644 --- a/openbsc/tests/mgcp/mgcp_transcoding_test.c +++ b/openbsc/tests/mgcp/mgcp_transcoding_test.c @@ -17,7 +17,7 @@ #error "Requires MGCP transcoding enabled (see --enable-mgcp-transcoding)" #endif -#include "src/osmo-bsc_mgcp/mgcp_transcode.h" +#include "openbsc/mgcp_transcode.h" uint8_t *audio_frame_l16[] = { }; -- 1.7.9.5 From holger at freyther.de Wed May 14 05:49:38 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Wed, 14 May 2014 07:49:38 +0200 Subject: [PATCH 10/11] mgcp: Move transcoding to libmgcp In-Reply-To: <1399891147-31419-10-git-send-email-jerlbeck@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> <1399891147-31419-10-git-send-email-jerlbeck@sysmocom.de> Message-ID: <20140514054938.GJ26057@xiaoyu.lan> On Mon, May 12, 2014 at 12:39:06PM +0200, Jacob Erlbeck wrote: > This patch moves the files relevant to transcoding from > src/osmo-bsc_mgcp to src/libmgcp and src/include/openbsc. Makefiles > and include directives are being updated accordingly. Can you try to create this patch with the -M option. It will re-direct renames. I assume the actual change is limited to Makefiles. From jerlbeck at sysmocom.de Thu May 15 07:59:28 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Thu, 15 May 2014 09:59:28 +0200 Subject: [PATCH 10/11] mgcp: Move transcoding to libmgcp In-Reply-To: <20140514054938.GJ26057@xiaoyu.lan> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> <1399891147-31419-10-git-send-email-jerlbeck@sysmocom.de> <20140514054938.GJ26057@xiaoyu.lan> Message-ID: <537473E0.4060007@sysmocom.de> On 14.05.2014 07:49, Holger Hans Peter Freyther wrote: > On Mon, May 12, 2014 at 12:39:06PM +0200, Jacob Erlbeck wrote: >> This patch moves the files relevant to transcoding from >> src/osmo-bsc_mgcp to src/libmgcp and src/include/openbsc. Makefiles >> and include directives are being updated accordingly. > > Can you try to create this patch with the -M option. It will re-direct > renames. I assume the actual change is limited to Makefiles. No, since the header file has moved also, some include directives have to be adjusted, too. -- - Jacob Erlbeck http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Schivelbeiner Str. 5 * 10439 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte From jerlbeck at sysmocom.de Mon May 12 10:39:07 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Mon, 12 May 2014 12:39:07 +0200 Subject: [PATCH 11/11] mgcp: Set net_end audio params in recvonly mode In-Reply-To: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1399891147-31419-11-git-send-email-jerlbeck@sysmocom.de> Currently, if there is no SDP data in the MGCP message received from the net, the fields containing audio encoding information are not set in net_end. So in recvonly mode transcoding would not be set up correctly. This patch changes the implementation of the code handling CRCX and MDCX to use the codec signalled in the MGCP local connection options (field 'a:') if there isn't any SDP data. This is only halfway negotiation, because the codec is used blindly and not matched against the supported ones. Sponsored-by: On-Waves ehf --- openbsc/include/openbsc/mgcp_internal.h | 1 + openbsc/src/libmgcp/mgcp_protocol.c | 35 ++++++++++++++++++++++++++++--- openbsc/tests/mgcp/mgcp_test.c | 7 +++++++ openbsc/tests/mgcp/mgcp_test.ok | 5 +++++ 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h index c7bc2a8..e877026 100644 --- a/openbsc/include/openbsc/mgcp_internal.h +++ b/openbsc/include/openbsc/mgcp_internal.h @@ -124,6 +124,7 @@ struct mgcp_rtp_tap { struct mgcp_lco { char *string; + char *codec; int pkt_period_min; /* time in ms */ int pkt_period_max; /* time in ms */ }; diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c index f26587e..104ad00 100644 --- a/openbsc/src/libmgcp/mgcp_protocol.c +++ b/openbsc/src/libmgcp/mgcp_protocol.c @@ -582,7 +582,8 @@ static int set_audio_info(struct mgcp_rtp_end *rtp, talloc_free(rtp->audio_name); rtp->audio_name = NULL; - rtp->payload_type = payload_type; + if (payload_type >= 0) + rtp->payload_type = payload_type; if (!audio_name) { switch (payload_type) { @@ -597,7 +598,7 @@ static int set_audio_info(struct mgcp_rtp_end *rtp, } if (sscanf(audio_name, "%63[^/]/%d/%d", - audio_codec, &rate, &channels) < 2) + audio_codec, &rate, &channels) < 1) return -EINVAL; rtp->rate = rate; @@ -610,6 +611,20 @@ static int set_audio_info(struct mgcp_rtp_end *rtp, rtp->frame_duration_den = 1000; } + if (payload_type < 0) { + payload_type = 96; + if (rate == 8000 && channels == 1) { + if (!strcmp(audio_codec, "GSM")) + payload_type = 3; + else if (!strcmp(audio_codec, "PCMA")) + payload_type = 8; + else if (!strcmp(audio_codec, "G729")) + payload_type = 18; + } + + rtp->payload_type = payload_type; + } + if (channels != 1) LOGP(DMGCP, LOGL_NOTICE, "Channels != 1 in SDP: '%s'\n", audio_name); @@ -781,9 +796,12 @@ static int parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p) static void set_local_cx_options(void *ctx, struct mgcp_lco *lco, const char *options) { - char *p_opt; + char *p_opt, *a_opt; + char codec[9]; talloc_free(lco->string); + talloc_free(lco->codec); + lco->codec = NULL; lco->pkt_period_min = lco->pkt_period_max = 0; lco->string = talloc_strdup(ctx, options ? options : ""); @@ -791,6 +809,10 @@ static void set_local_cx_options(void *ctx, struct mgcp_lco *lco, if (p_opt && sscanf(p_opt, "p:%d-%d", &lco->pkt_period_min, &lco->pkt_period_max) == 1) lco->pkt_period_max = lco->pkt_period_min; + + a_opt = strstr(lco->string, "a:"); + if (a_opt && sscanf(a_opt, "a:%8[^,]", codec) == 1) + lco->codec = talloc_strdup(ctx, codec); } void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change, @@ -924,6 +946,8 @@ mgcp_header_done: tcfg->audio_fmtp_extra); if (have_sdp) parse_sdp_data(&endp->net_end, p); + else if (endp->local_options.codec) + set_audio_info(&endp->net_end, -1, endp->local_options.codec); if (p->cfg->bts_force_ptime) { endp->bts_end.packet_duration_ms = p->cfg->bts_force_ptime; @@ -977,6 +1001,7 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p) struct mgcp_endpoint *endp = p->endp; int error_code = 500; int silent = 0; + int have_sdp = 0; char *line; const char *local_options = NULL; @@ -1016,6 +1041,7 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p) break; case '\0': /* SDP file begins */ + have_sdp = 1; parse_sdp_data(&endp->net_end, p); /* This will exhaust p->save, so the loop will * terminate next time. @@ -1031,6 +1057,9 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p) set_local_cx_options(endp->tcfg->endpoints, &endp->local_options, local_options); + if (!have_sdp && endp->local_options.codec) + set_audio_info(&endp->net_end, -1, endp->local_options.codec); + setup_rtp_processing(endp); /* policy CB */ diff --git a/openbsc/tests/mgcp/mgcp_test.c b/openbsc/tests/mgcp/mgcp_test.c index 498a1d8..0552c72 100644 --- a/openbsc/tests/mgcp/mgcp_test.c +++ b/openbsc/tests/mgcp/mgcp_test.c @@ -168,6 +168,12 @@ static void test_strline(void) "a=rtpmap:99 AMR/8000\r\n" \ "a=ptime:40\r\n" +#define MDCX4_RO "MDCX 18983221 1 at mgw MGCP 1.0\r\n" \ + "M: recvonly\r" \ + "C: 2\r\n" \ + "I: 1\r\n" \ + "L: p:20, a:AMR, nt:IN\r\n" + #define SHORT2 "CRCX 1" #define SHORT2_RET "510 000000 FAIL\r\n" #define SHORT3 "CRCX 1 1 at mgw" @@ -257,6 +263,7 @@ static const struct mgcp_test tests[] = { { "MDCX4_PT2", MDCX4_PT2, MDCX4_RET("18983218"), 99, 126 }, { "MDCX4_PT3", MDCX4_PT3, MDCX4_RET("18983219"), 99, 126 }, { "MDCX4_SO", MDCX4_SO, MDCX4_RET("18983220"), 99, 126 }, + { "MDCX4_RO", MDCX4_RO, MDCX4_RET("18983221"), PTYPE_IGNORE, 126 }, { "DLCX", DLCX, DLCX_RET, -1, -1 }, { "CRCX_ZYN", CRCX_ZYN, CRCX_ZYN_RET, 97, 126 }, { "EMPTY", EMPTY, EMPTY_RET }, diff --git a/openbsc/tests/mgcp/mgcp_test.ok b/openbsc/tests/mgcp/mgcp_test.ok index 3901cfb..7301a81 100644 --- a/openbsc/tests/mgcp/mgcp_test.ok +++ b/openbsc/tests/mgcp/mgcp_test.ok @@ -49,6 +49,11 @@ Testing MDCX4_SO Detected packet duration: 40 Requested packetetization period: 20-20 Connection mode: 2: SEND +Testing MDCX4_RO +Dummy packets: 1 +Packet duration not set +Requested packetetization period: 20-20 +Connection mode: 1: RECV Testing DLCX Detected packet duration: 20 Requested packetization period not set -- 1.7.9.5 From jerlbeck at sysmocom.de Thu May 15 08:29:09 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Thu, 15 May 2014 10:29:09 +0200 Subject: [PATCH 01/11] mgcp: Add callbacks for payload processing In-Reply-To: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1400142559-26788-1-git-send-email-jerlbeck@sysmocom.de> This patch adds the callbacks rtp_processing_cb and setup_rtp_processing_cb to mgcp_config to support arbitrary RTP payload processing. Sponsored-by: On-Waves ehf --- openbsc/include/openbsc/mgcp.h | 10 +++++++++ openbsc/include/openbsc/mgcp_internal.h | 8 ++++++++ openbsc/src/libmgcp/mgcp_network.c | 20 +++++++++++++++--- openbsc/src/libmgcp/mgcp_protocol.c | 34 ++++++++++++++++++++++++++++++- 4 files changed, 68 insertions(+), 4 deletions(-) diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h index 1d74078..6ba0769 100644 --- a/openbsc/include/openbsc/mgcp.h +++ b/openbsc/include/openbsc/mgcp.h @@ -65,6 +65,7 @@ static inline int rtp_calculate_port(int multiplex, int base) struct mgcp_endpoint; struct mgcp_config; struct mgcp_trunk_config; +struct mgcp_rtp_end; #define MGCP_ENDP_CRCX 1 #define MGCP_ENDP_DLCX 2 @@ -86,6 +87,11 @@ typedef int (*mgcp_policy)(struct mgcp_trunk_config *cfg, int endpoint, int stat typedef int (*mgcp_reset)(struct mgcp_trunk_config *cfg); typedef int (*mgcp_rqnt)(struct mgcp_endpoint *endp, char tone); +typedef int (*mgcp_processing)(struct mgcp_rtp_end *dst_end, + char *data, int *len, int buf_size); +typedef int (*mgcp_processing_setup)(struct mgcp_endpoint *endp, + struct mgcp_rtp_end *dst_end, + struct mgcp_rtp_end *src_end); #define PORT_ALLOC_STATIC 0 #define PORT_ALLOC_DYNAMIC 1 @@ -156,6 +162,10 @@ struct mgcp_config { struct in_addr transcoder_in; int transcoder_remote_base; + /* RTP processing */ + mgcp_processing rtp_processing_cb; + mgcp_processing_setup setup_rtp_processing_cb; + struct osmo_wqueue gw_fd; struct mgcp_port_range bts_ports; diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h index 9b97165..56c280d 100644 --- a/openbsc/include/openbsc/mgcp_internal.h +++ b/openbsc/include/openbsc/mgcp_internal.h @@ -91,6 +91,7 @@ struct mgcp_rtp_end { /* RTP patching */ int force_constant_ssrc; /* -1: always, 0: don't, 1: once */ int force_aligned_timing; + void *rtp_process_data; /* * Each end has a socket... @@ -197,5 +198,12 @@ void mgcp_state_calc_loss(struct mgcp_rtp_state *s, struct mgcp_rtp_end *, uint32_t *expected, int *loss); uint32_t mgcp_state_calc_jitter(struct mgcp_rtp_state *); +/* payload processing default functions */ +int mgcp_rtp_processing_default(struct mgcp_rtp_end *dst_end, + char *data, int *len, int buf_size); + +int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp, + struct mgcp_rtp_end *dst_end, + struct mgcp_rtp_end *src_end); #endif diff --git a/openbsc/src/libmgcp/mgcp_network.c b/openbsc/src/libmgcp/mgcp_network.c index 8a5656a..4d1ad35 100644 --- a/openbsc/src/libmgcp/mgcp_network.c +++ b/openbsc/src/libmgcp/mgcp_network.c @@ -77,6 +77,7 @@ struct rtp_hdr { #define RTP_SEQ_MOD (1 << 16) #define RTP_MAX_DROPOUT 3000 #define RTP_MAX_MISORDER 100 +#define RTP_BUF_SIZE 4096 enum { @@ -347,6 +348,18 @@ static int align_rtp_timestamp_offset(struct mgcp_endpoint *endp, return timestamp_error; } +int mgcp_rtp_processing_default(struct mgcp_rtp_end *dst_end, + char *data, int *len, int buf_size) +{ + return 0; +} + +int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp, + struct mgcp_rtp_end *dst_end, + struct mgcp_rtp_end *src_end) +{ + return 0; +} /** * The RFC 3550 Appendix A assumes there are multiple sources but @@ -597,6 +610,7 @@ static int mgcp_send(struct mgcp_endpoint *endp, int dest, int is_rtp, rtp_end->dropped_packets += 1; else if (is_rtp) { mgcp_patch_and_count(endp, rtp_state, rtp_end, addr, buf, rc); + endp->cfg->rtp_processing_cb(rtp_end, buf, &rc, RTP_BUF_SIZE); forward_data(rtp_end->rtp.fd, &endp->taps[tap_idx], buf, rc); return mgcp_udp_send(rtp_end->rtp.fd, &rtp_end->addr, @@ -635,7 +649,7 @@ static int receive_from(struct mgcp_endpoint *endp, int fd, struct sockaddr_in * static int rtp_data_net(struct osmo_fd *fd, unsigned int what) { - char buf[4096]; + char buf[RTP_BUF_SIZE]; struct sockaddr_in addr; struct mgcp_endpoint *endp; int rc, proto; @@ -719,7 +733,7 @@ static void discover_bts(struct mgcp_endpoint *endp, int proto, struct sockaddr_ static int rtp_data_bts(struct osmo_fd *fd, unsigned int what) { - char buf[4096]; + char buf[RTP_BUF_SIZE]; struct sockaddr_in addr; struct mgcp_endpoint *endp; int rc, proto; @@ -781,7 +795,7 @@ static int rtp_data_bts(struct osmo_fd *fd, unsigned int what) static int rtp_data_transcoder(struct mgcp_rtp_end *end, struct mgcp_endpoint *_endp, int dest, struct osmo_fd *fd) { - char buf[4096]; + char buf[RTP_BUF_SIZE]; struct sockaddr_in addr; struct mgcp_config *cfg; int rc, proto; diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c index 5c88c9d..0f8614c 100644 --- a/openbsc/src/libmgcp/mgcp_protocol.c +++ b/openbsc/src/libmgcp/mgcp_protocol.c @@ -107,6 +107,8 @@ static struct msgb *handle_noti_req(struct mgcp_parse_data *data); static void create_transcoder(struct mgcp_endpoint *endp); static void delete_transcoder(struct mgcp_endpoint *endp); +static void setup_rtp_processing(struct mgcp_endpoint *endp); + static int mgcp_analyze_header(struct mgcp_parse_data *parse, char *data); static uint32_t generate_call_id(struct mgcp_config *cfg) @@ -827,8 +829,10 @@ mgcp_header_done: endp->bts_end.payload_type = tcfg->audio_payload; endp->bts_end.fmtp_extra = talloc_strdup(tcfg->endpoints, tcfg->audio_fmtp_extra); - if (have_sdp) + if (have_sdp) { parse_sdp_data(&endp->net_end, p); + setup_rtp_processing(endp); + } /* policy CB */ if (p->cfg->policy_cb) { @@ -929,6 +933,8 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p) set_local_cx_options(endp->tcfg->endpoints, &endp->local_options, local_options); + setup_rtp_processing(endp); + /* policy CB */ if (p->cfg->policy_cb) { int rc; @@ -1169,6 +1175,9 @@ struct mgcp_config *mgcp_config_alloc(void) cfg->bts_ports.base_port = RTP_PORT_DEFAULT; cfg->net_ports.base_port = RTP_PORT_NET_DEFAULT; + cfg->rtp_processing_cb = &mgcp_rtp_processing_default; + cfg->setup_rtp_processing_cb = &mgcp_setup_rtp_processing_default; + /* default trunk handling */ cfg->trunk.cfg = cfg; cfg->trunk.trunk_nr = 0; @@ -1234,6 +1243,8 @@ static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end) end->local_alloc = -1; talloc_free(end->fmtp_extra); end->fmtp_extra = NULL; + talloc_free(end->rtp_process_data); + end->rtp_process_data = NULL; /* Set default values */ end->frame_duration_num = DEFAULT_RTP_AUDIO_FRAME_DUR_NUM; @@ -1388,6 +1399,27 @@ int mgcp_send_reset_ep(struct mgcp_endpoint *endp, int endpoint) return send_agent(endp->cfg, buf, len); } +static void setup_rtp_processing(struct mgcp_endpoint *endp) +{ + struct mgcp_config *cfg = endp->cfg; + + if (endp->type != MGCP_RTP_DEFAULT) + return; + + if (endp->conn_mode == MGCP_CONN_LOOPBACK) + return; + + if (endp->conn_mode & MGCP_CONN_SEND_ONLY) + cfg->setup_rtp_processing_cb(endp, &endp->net_end, &endp->bts_end); + else + cfg->setup_rtp_processing_cb(endp, &endp->net_end, NULL); + + if (endp->conn_mode & MGCP_CONN_RECV_ONLY) + cfg->setup_rtp_processing_cb(endp, &endp->bts_end, &endp->net_end); + else + cfg->setup_rtp_processing_cb(endp, &endp->bts_end, NULL); +} + static void create_transcoder(struct mgcp_endpoint *endp) { int port; -- 1.7.9.5 From jerlbeck at sysmocom.de Thu May 15 08:29:10 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Thu, 15 May 2014 10:29:10 +0200 Subject: [PATCH 02/11] mgcp: Add audio info fields to struct mgcp_rtp_end In-Reply-To: <1400142559-26788-1-git-send-email-jerlbeck@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> <1400142559-26788-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1400142559-26788-2-git-send-email-jerlbeck@sysmocom.de> This patch adds the fields channels, subtype_name, and audio_name to the struct. The field audio_name contains the full string that has been used for the last part of a SDP a=rtpmap line. The others contain decoded parts of that string. If no a=rtpmap line has been given (e.g. because dynamic payload types are not used), values are assigned when the payload type matches one of the predefined ones (GSM, G729, PCMA). Sponsored-by: On-Waves ehf --- openbsc/include/openbsc/mgcp_internal.h | 3 ++ openbsc/src/libmgcp/mgcp_protocol.c | 82 +++++++++++++++++++++++-------- 2 files changed, 64 insertions(+), 21 deletions(-) diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h index 56c280d..72ac8e9 100644 --- a/openbsc/include/openbsc/mgcp_internal.h +++ b/openbsc/include/openbsc/mgcp_internal.h @@ -81,11 +81,14 @@ struct mgcp_rtp_end { /* per endpoint data */ int payload_type; uint32_t rate; + int channels; uint32_t frame_duration_num; uint32_t frame_duration_den; int frames_per_packet; uint32_t packet_duration_ms; char *fmtp_extra; + char *audio_name; + char *subtype_name; int output_enabled; /* RTP patching */ diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c index 0f8614c..3960c88 100644 --- a/openbsc/src/libmgcp/mgcp_protocol.c +++ b/openbsc/src/libmgcp/mgcp_protocol.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -77,6 +78,7 @@ char *strline_r(char *str, char **saveptr) #define DEFAULT_RTP_AUDIO_FRAME_DUR_DEN 1000 #define DEFAULT_RTP_AUDIO_PACKET_DURATION_MS 20 #define DEFAULT_RTP_AUDIO_DEFAULT_RATE 8000 +#define DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS 1 static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end); @@ -231,6 +233,8 @@ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp, { const char *addr = endp->cfg->local_ip; const char *fmtp_extra = endp->bts_end.fmtp_extra; + const char *audio_name = endp->bts_end.audio_name; + int payload_type = endp->bts_end.payload_type; char sdp_record[4096]; int len; @@ -244,11 +248,12 @@ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp, "c=IN IP4 %s\r\n" "t=0 0\r\n" "m=audio %d RTP/AVP %d\r\n" - "a=rtpmap:%d %s\r\n" + "a=rtpmap:%d%s%s\r\n" "%s%s", endp->ci, endp->ci, addr, addr, - endp->net_end.local_port, endp->bts_end.payload_type, - endp->bts_end.payload_type, endp->tcfg->audio_name, + endp->net_end.local_port, payload_type, + payload_type, + audio_name ? " " : "", audio_name ? audio_name : "", fmtp_extra ? fmtp_extra : "", fmtp_extra ? "\r\n" : ""); if (len < 0 || len >= sizeof(sdp_record)) @@ -514,6 +519,47 @@ static int parse_conn_mode(const char *msg, struct mgcp_endpoint *endp) return ret; } +static int set_audio_info(void *ctx, struct mgcp_rtp_end *rtp, + int payload_type, const char *audio_name) +{ + int rate = 8000; + int channels = 1; + char audio_codec[64]; + + talloc_free(rtp->subtype_name); + rtp->subtype_name = NULL; + talloc_free(rtp->audio_name); + rtp->audio_name = NULL; + + rtp->payload_type = payload_type; + + if (!audio_name) { + switch (payload_type) { + case 3: audio_name = "GSM/8000/1"; break; + case 8: audio_name = "PCMA/8000/1"; break; + case 18: audio_name = "G729/8000/1"; break; + default: + rtp->rate = 8000; + rtp->channels = 1; + return 0; + } + } + + if (sscanf(audio_name, "%63[^/]/%d/%d", + audio_codec, &rate, &channels) < 2) + return -EINVAL; + + rtp->rate = rate; + rtp->channels = channels; + rtp->subtype_name = talloc_strdup(ctx, audio_codec); + rtp->audio_name = talloc_strdup(ctx, audio_name); + if (channels != 1) + LOGP(DMGCP, LOGL_NOTICE, + "Channels != 1 in SDP: '%s'\n", audio_name); + + return 0; +} + static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_rtp_end *end, struct mgcp_port_range *range, int (*alloc)(struct mgcp_endpoint *endp, int port)) @@ -600,29 +646,18 @@ static int parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p) break; case 'a': { int payload; - int rate; - int channels = 1; int ptime, ptime2 = 0; char audio_name[64]; - char audio_codec[64]; if (audio_payload == -1) break; - if (sscanf(line, "a=rtpmap:%d %64s", + if (sscanf(line, "a=rtpmap:%d %63s", &payload, audio_name) == 2) { if (payload != audio_payload) break; - if (sscanf(audio_name, "%[^/]/%d/%d", - audio_codec, &rate, &channels) < 2) - break; - - rtp->rate = rate; - if (channels != 1) - LOGP(DMGCP, LOGL_NOTICE, - "Channels != 1 in SDP: '%s' on 0x%x\n", - line, ENDPOINT_NUMBER(p->endp)); + set_audio_info(p->cfg, rtp, payload, audio_name); } else if (sscanf(line, "a=ptime:%d-%d", &ptime, &ptime2) >= 1) { if (ptime2 > 0 && ptime2 != ptime) @@ -645,8 +680,8 @@ static int parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p) &port, &audio_payload) == 2) { rtp->rtp_port = htons(port); rtp->rtcp_port = htons(port + 1); - rtp->payload_type = audio_payload; found_media = 1; + set_audio_info(p->cfg, rtp, audio_payload, NULL); } break; } @@ -826,7 +861,7 @@ mgcp_header_done: endp->allocated = 1; /* set up RTP media parameters */ - endp->bts_end.payload_type = tcfg->audio_payload; + set_audio_info(p->cfg, &endp->bts_end, tcfg->audio_payload, tcfg->audio_name); endp->bts_end.fmtp_extra = talloc_strdup(tcfg->endpoints, tcfg->audio_fmtp_extra); if (have_sdp) { @@ -1252,6 +1287,7 @@ static void mgcp_rtp_end_reset(struct mgcp_rtp_end *end) end->frames_per_packet = 0; /* unknown */ end->packet_duration_ms = DEFAULT_RTP_AUDIO_PACKET_DURATION_MS; end->rate = DEFAULT_RTP_AUDIO_DEFAULT_RATE; + end->channels = DEFAULT_RTP_AUDIO_DEFAULT_CHANNELS; end->output_enabled = 0; } @@ -1329,6 +1365,9 @@ static void send_msg(struct mgcp_endpoint *endp, int endpoint, int port, { char buf[2096]; int len; + const char *fmtp_extra = endp->bts_end.fmtp_extra; + const char *audio_name = endp->bts_end.audio_name; + int payload_type = endp->bts_end.payload_type; /* hardcoded to AMR right now, we do not know the real type at this point */ len = snprintf(buf, sizeof(buf), @@ -1338,10 +1377,11 @@ static void send_msg(struct mgcp_endpoint *endp, int endpoint, int port, "\r\n" "c=IN IP4 %s\r\n" "m=audio %d RTP/AVP %d\r\n" - "a=rtpmap:%d %s\r\n", + "a=rtpmap:%d%s%s\r\n", msg, endpoint, mode, endp->cfg->source_addr, - port, endp->tcfg->audio_payload, - endp->tcfg->audio_payload, endp->tcfg->audio_name); + port, payload_type, + payload_type, + audio_name ? " " : "", audio_name ? audio_name : ""); if (len < 0) return; -- 1.7.9.5 From holger at freyther.de Thu May 15 19:28:20 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Thu, 15 May 2014 21:28:20 +0200 Subject: [PATCH 02/11] mgcp: Add audio info fields to struct mgcp_rtp_end In-Reply-To: <1400142559-26788-2-git-send-email-jerlbeck@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> <1400142559-26788-1-git-send-email-jerlbeck@sysmocom.de> <1400142559-26788-2-git-send-email-jerlbeck@sysmocom.de> Message-ID: <20140515192820.GL26903@xiaoyu.lan> On Thu, May 15, 2014 at 10:29:10AM +0200, Jacob Erlbeck wrote: > - if (sscanf(line, "a=rtpmap:%d %64s", > + if (sscanf(line, "a=rtpmap:%d %63s", cppcheck is warning about the usage of 64 here. It warns about some of the other scanf as well. Please have a look at it by running cppcheck. From holger at freyther.de Thu May 15 19:34:18 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Thu, 15 May 2014 21:34:18 +0200 Subject: [PATCH 02/11] mgcp: Add audio info fields to struct mgcp_rtp_end In-Reply-To: <1400142559-26788-2-git-send-email-jerlbeck@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> <1400142559-26788-1-git-send-email-jerlbeck@sysmocom.de> <1400142559-26788-2-git-send-email-jerlbeck@sysmocom.de> Message-ID: <20140515193418.GN26903@xiaoyu.lan> On Thu, May 15, 2014 at 10:29:10AM +0200, Jacob Erlbeck wrote: Hi, > +static int set_audio_info(void *ctx, struct mgcp_rtp_end *rtp, > + int payload_type, const char *audio_name) > +{ ... > + talloc_free(rtp->subtype_name); > + rtp->subtype_name = NULL; > + talloc_free(rtp->audio_name); > + rtp->audio_name = NULL; ... > @@ -600,29 +646,18 @@ static int parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p) ... > + set_audio_info(p->cfg, rtp, payload, audio_name); > } else if (sscanf(line, "a=ptime:%d-%d", ... > + set_audio_info(p->cfg, rtp, audio_payload, NULL); > - endp->bts_end.payload_type = tcfg->audio_payload; > + set_audio_info(p->cfg, &endp->bts_end, tcfg->audio_payload, tcfg->audio_name); I raised this before as well. So for a CRCX MDCX DLCX procedure. We might have endp->bts_end->subtype_name still with an allocated string. Please make reset endpoint give up all the data. From jerlbeck at sysmocom.de Fri May 16 11:17:12 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Fri, 16 May 2014 13:17:12 +0200 Subject: [PATCH 02/11] mgcp: Add audio info fields to struct mgcp_rtp_end In-Reply-To: <20140515193418.GN26903@xiaoyu.lan> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> <1400142559-26788-1-git-send-email-jerlbeck@sysmocom.de> <1400142559-26788-2-git-send-email-jerlbeck@sysmocom.de> <20140515193418.GN26903@xiaoyu.lan> Message-ID: <5375F3B8.2070403@sysmocom.de> On 15.05.2014 21:34, Holger Hans Peter Freyther wrote: > > I raised this before as well. Yes you did, and I implemented it accordingly. But I apparently lost it somewhere in rebase hell :-( Thanks for spotting again. > So for a > > CRCX > MDCX > DLCX > > procedure. We might have endp->bts_end->subtype_name still with an > allocated string. Please make reset endpoint give up all the data. > -- - Jacob Erlbeck http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Schivelbeiner Str. 5 * 10439 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte From jerlbeck at sysmocom.de Thu May 15 08:29:11 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Thu, 15 May 2014 10:29:11 +0200 Subject: [PATCH 03/11] mgcp: Add a function to get media info for MGCP responses In-Reply-To: <1400142559-26788-1-git-send-email-jerlbeck@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> <1400142559-26788-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1400142559-26788-3-git-send-email-jerlbeck@sysmocom.de> This patch adds the get_net_downlink_format_cb() callback to provide payload_type, subtype_name, and fmtp_extra suitable for use in a MGCP response sent to the network. Per default, the BTS side values are returned since these must be honoured by the net peer when sending audio to the media gateway (unless transcoding is done). Sponsored-by: On-Waves ehf --- openbsc/include/openbsc/mgcp.h | 8 ++++++++ openbsc/include/openbsc/mgcp_internal.h | 5 +++++ openbsc/src/libmgcp/mgcp_network.c | 13 +++++++++++++ openbsc/src/libmgcp/mgcp_protocol.c | 20 ++++++++++++++------ 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h index 6ba0769..b595aba 100644 --- a/openbsc/include/openbsc/mgcp.h +++ b/openbsc/include/openbsc/mgcp.h @@ -92,6 +92,12 @@ typedef int (*mgcp_processing)(struct mgcp_rtp_end *dst_end, typedef int (*mgcp_processing_setup)(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end, struct mgcp_rtp_end *src_end); + +typedef void (*mgcp_get_format)(struct mgcp_endpoint *endp, + int *payload_type, + const char**subtype_name, + const char**fmtp_extra); + #define PORT_ALLOC_STATIC 0 #define PORT_ALLOC_DYNAMIC 1 @@ -166,6 +172,8 @@ struct mgcp_config { mgcp_processing rtp_processing_cb; mgcp_processing_setup setup_rtp_processing_cb; + mgcp_get_format get_net_downlink_format_cb; + struct osmo_wqueue gw_fd; struct mgcp_port_range bts_ports; diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h index 72ac8e9..e74b9fa 100644 --- a/openbsc/include/openbsc/mgcp_internal.h +++ b/openbsc/include/openbsc/mgcp_internal.h @@ -209,4 +209,9 @@ int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end, struct mgcp_rtp_end *src_end); +void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp, + int *payload_type, + const char**subtype_name, + const char**fmtp_extra); + #endif diff --git a/openbsc/src/libmgcp/mgcp_network.c b/openbsc/src/libmgcp/mgcp_network.c index 4d1ad35..dcbb97a 100644 --- a/openbsc/src/libmgcp/mgcp_network.c +++ b/openbsc/src/libmgcp/mgcp_network.c @@ -361,6 +361,19 @@ int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp, return 0; } +void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp, + int *payload_type, + const char**audio_name, + const char**fmtp_extra) +{ + /* Use the BTS side parameters when passing the SDP data (for + * downlink) to the net peer. + */ + *payload_type = endp->bts_end.payload_type; + *audio_name = endp->bts_end.audio_name; + *fmtp_extra = endp->bts_end.fmtp_extra; +} + /** * The RFC 3550 Appendix A assumes there are multiple sources but * some of the supported endpoints (e.g. the nanoBTS) can only handle diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c index 3960c88..215c2ee 100644 --- a/openbsc/src/libmgcp/mgcp_protocol.c +++ b/openbsc/src/libmgcp/mgcp_protocol.c @@ -232,12 +232,15 @@ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp, const char *msg, const char *trans_id) { const char *addr = endp->cfg->local_ip; - const char *fmtp_extra = endp->bts_end.fmtp_extra; - const char *audio_name = endp->bts_end.audio_name; - int payload_type = endp->bts_end.payload_type; + const char *fmtp_extra; + const char *audio_name; + int payload_type; char sdp_record[4096]; int len; + endp->cfg->get_net_downlink_format_cb(endp, &payload_type, + &audio_name, &fmtp_extra); + if (!addr) addr = endp->cfg->source_addr; @@ -1213,6 +1216,8 @@ struct mgcp_config *mgcp_config_alloc(void) cfg->rtp_processing_cb = &mgcp_rtp_processing_default; cfg->setup_rtp_processing_cb = &mgcp_setup_rtp_processing_default; + cfg->get_net_downlink_format_cb = &mgcp_get_net_downlink_format_default; + /* default trunk handling */ cfg->trunk.cfg = cfg; cfg->trunk.trunk_nr = 0; @@ -1365,9 +1370,12 @@ static void send_msg(struct mgcp_endpoint *endp, int endpoint, int port, { char buf[2096]; int len; - const char *fmtp_extra = endp->bts_end.fmtp_extra; - const char *audio_name = endp->bts_end.audio_name; - int payload_type = endp->bts_end.payload_type; + const char *fmtp_extra; + const char *audio_name; + int payload_type; + + endp->cfg->get_net_downlink_format_cb(endp, &payload_type, + &audio_name, &fmtp_extra); /* hardcoded to AMR right now, we do not know the real type at this point */ len = snprintf(buf, sizeof(buf), -- 1.7.9.5 From jerlbeck at sysmocom.de Thu May 15 08:29:12 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Thu, 15 May 2014 10:29:12 +0200 Subject: [PATCH 04/11] mgcp: Only include SDP lines with valid content In-Reply-To: <1400142559-26788-1-git-send-email-jerlbeck@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> <1400142559-26788-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1400142559-26788-4-git-send-email-jerlbeck@sysmocom.de> Don't show media related lines if the payload type has not been set. Don't show a 'a=rtpmap' line if the audio_name has not been set. This patch unifies the SDP generation of create_response_with_sdp() and send_msg(). Sponsored-by: On-Waves ehf --- openbsc/src/libmgcp/mgcp_protocol.c | 129 +++++++++++++++++++++++------------ 1 file changed, 87 insertions(+), 42 deletions(-) diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c index 215c2ee..f0d94c8 100644 --- a/openbsc/src/libmgcp/mgcp_protocol.c +++ b/openbsc/src/libmgcp/mgcp_protocol.c @@ -228,55 +228,103 @@ static struct msgb *create_err_response(struct mgcp_endpoint *endp, return create_resp(endp, code, " FAIL", msg, trans, NULL, NULL); } -static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp, - const char *msg, const char *trans_id) +static int write_response_sdp(struct mgcp_endpoint *endp, + char *sdp_record, size_t size, const char *addr) { - const char *addr = endp->cfg->local_ip; const char *fmtp_extra; const char *audio_name; int payload_type; - char sdp_record[4096]; int len; + int nchars; endp->cfg->get_net_downlink_format_cb(endp, &payload_type, &audio_name, &fmtp_extra); - if (!addr) - addr = endp->cfg->source_addr; - - len = snprintf(sdp_record, sizeof(sdp_record) - 1, - "I: %u\n\n" + len = snprintf(sdp_record, size, "v=0\r\n" "o=- %u 23 IN IP4 %s\r\n" "c=IN IP4 %s\r\n" - "t=0 0\r\n" - "m=audio %d RTP/AVP %d\r\n" - "a=rtpmap:%d%s%s\r\n" - "%s%s", - endp->ci, endp->ci, addr, addr, - endp->net_end.local_port, payload_type, - payload_type, - audio_name ? " " : "", audio_name ? audio_name : "", - fmtp_extra ? fmtp_extra : "", fmtp_extra ? "\r\n" : ""); - - if (len < 0 || len >= sizeof(sdp_record)) + "t=0 0\r\n", + endp->ci, addr, addr); + + if (len < 0 || len >= size) goto buffer_too_small; + if (payload_type >= 0) { + nchars = snprintf(sdp_record + len, size - len, + "m=audio %d RTP/AVP %d\r\n", + endp->net_end.local_port, payload_type); + if (nchars < 0 || nchars >= size - len) + goto buffer_too_small; + + len += nchars; + + if (audio_name) { + nchars = snprintf(sdp_record + len, size - len, + "a=rtpmap:%d %s\r\n", + payload_type, audio_name); + + if (nchars < 0 || nchars >= size - len) + goto buffer_too_small; + + len += nchars; + } + + if (fmtp_extra) { + nchars = snprintf(sdp_record + len, size - len, + "a=rtpmap:%d %s\r\n", + payload_type, audio_name); + + if (nchars < 0 || nchars >= size - len) + goto buffer_too_small; + + len += nchars; + } + } if (endp->bts_end.packet_duration_ms > 0 && endp->tcfg->audio_send_ptime) { - int nchars = snprintf(sdp_record + len, sizeof(sdp_record) - len, - "a=ptime:%d\r\n", - endp->bts_end.packet_duration_ms); - if (nchars < 0 || nchars >= sizeof(sdp_record) - len) + nchars = snprintf(sdp_record + len, size - len, + "a=ptime:%d\r\n", + endp->bts_end.packet_duration_ms); + if (nchars < 0 || nchars >= size - len) goto buffer_too_small; len += nchars; } - return create_resp(endp, 200, " OK", msg, trans_id, NULL, sdp_record); + + return len; buffer_too_small: LOGP(DMGCP, LOGL_ERROR, "SDP buffer too small: %d (needed %d)\n", - sizeof(sdp_record), len); - return NULL; + size, len); + return -1; +} + +static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp, + const char *msg, const char *trans_id) +{ + const char *addr = endp->cfg->local_ip; + char sdp_record[4096]; + int len; + int nchars; + + if (!addr) + addr = endp->cfg->source_addr; + + len = snprintf(sdp_record, sizeof(sdp_record), "I: %u\n\n", endp->ci); + + if (len < 0) + return NULL; + + nchars = write_response_sdp(endp, sdp_record + len, + sizeof(sdp_record) - len - 1, addr); + if (nchars < 0) + return NULL; + + len += nchars; + + sdp_record[sizeof(sdp_record) - 1] = '\0'; + + return create_resp(endp, 200, " OK", msg, trans_id, NULL, sdp_record); } /* @@ -711,9 +759,10 @@ static int parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p) if (found_media) LOGP(DMGCP, LOGL_NOTICE, - "Got media info via SDP: port %d, payload %d, " + "Got media info via SDP: port %d, payload %d (%s), " "duration %d, addr %s\n", ntohs(rtp->rtp_port), rtp->payload_type, + rtp->subtype_name ? rtp->subtype_name : "unknown", rtp->packet_duration_ms, inet_ntoa(rtp->addr)); return found_media; @@ -1370,30 +1419,26 @@ static void send_msg(struct mgcp_endpoint *endp, int endpoint, int port, { char buf[2096]; int len; - const char *fmtp_extra; - const char *audio_name; - int payload_type; - - endp->cfg->get_net_downlink_format_cb(endp, &payload_type, - &audio_name, &fmtp_extra); + int nchars; /* hardcoded to AMR right now, we do not know the real type at this point */ len = snprintf(buf, sizeof(buf), "%s 42 %x at mgw MGCP 1.0\r\n" "C: 4256\r\n" "M: %s\r\n" - "\r\n" - "c=IN IP4 %s\r\n" - "m=audio %d RTP/AVP %d\r\n" - "a=rtpmap:%d%s%s\r\n", - msg, endpoint, mode, endp->cfg->source_addr, - port, payload_type, - payload_type, - audio_name ? " " : "", audio_name ? audio_name : ""); + "\r\n", + msg, endpoint, mode); if (len < 0) return; + nchars = write_response_sdp(endp, buf + len, sizeof(buf) + len - 1, + endp->cfg->source_addr); + if (nchars < 0) + return; + + len += nchars; + buf[sizeof(buf) - 1] = '\0'; send_trans(endp->cfg, buf, len); -- 1.7.9.5 From jerlbeck at sysmocom.de Thu May 15 08:29:13 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Thu, 15 May 2014 10:29:13 +0200 Subject: [PATCH 05/11] mgcp: Add RTP audio transcoding In-Reply-To: <1400142559-26788-1-git-send-email-jerlbeck@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> <1400142559-26788-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1400142559-26788-5-git-send-email-jerlbeck@sysmocom.de> This patch implements audio transcoding between the formats GSM, PCMA, L16, and optionally G.729. The feature needs to be enabled by using the autoconf option '--enable-mgcp-transcoding'. In this case mgcp_transcode.c will be compiled and linked to osmo-bsc_mgcp, and the transcoding functions provided will be registered as processing callbacks. If G.729 support is required, libcg729 needs to be installed and '--with-g729' must be passed to ./configure. Ticket: OW#1111 Sponsored-by: On-Waves ehf --- openbsc/configure.ac | 15 + openbsc/src/osmo-bsc_mgcp/Makefile.am | 10 +- openbsc/src/osmo-bsc_mgcp/g711common.h | 187 ++++++++++++ openbsc/src/osmo-bsc_mgcp/mgcp_main.c | 10 + openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c | 452 ++++++++++++++++++++++++++++ openbsc/src/osmo-bsc_mgcp/mgcp_transcode.h | 34 +++ 6 files changed, 706 insertions(+), 2 deletions(-) create mode 100644 openbsc/src/osmo-bsc_mgcp/g711common.h create mode 100644 openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c create mode 100644 openbsc/src/osmo-bsc_mgcp/mgcp_transcode.h diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 978f526..ead05af 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -56,6 +56,21 @@ fi AM_CONDITIONAL(BUILD_SMPP, test "x$osmo_ac_build_smpp" = "xyes") AC_SUBST(osmo_ac_build_smpp) +# Enable/disable transcoding within osmo-bsc_mgcp? +AC_ARG_ENABLE([mgcp-transcoding], [AS_HELP_STRING([--enable-mgcp-transcoding], [Build the MGCP gateway with internal transcoding enabled.])], + [osmo_ac_mgcp_transcoding="$enableval"],[osmo_ac_mgcp_transcoding="no"]) +AC_ARG_WITH([g729], [AS_HELP_STRING([--with-g729], [Enable G.729 encoding/decoding.])], [osmo_ac_with_g729="$withval"],[osmo_ac_with_g729="no"]) + +if test "$osmo_ac_mgcp_transcoding" = "yes" ; then + AC_SEARCH_LIBS(gsm_create, gsm) + if test "$osmo_ac_with_g729" = "yes" ; then + PKG_CHECK_MODULES(LIBBCG729, libbcg729 >= 0.1, [AC_DEFINE([HAVE_BCG729], [1], [Use bgc729 decoder/encoder])]) + fi + AC_DEFINE(BUILD_MGCP_TRANSCODING, 1, [Define if we want to build the MGCP gateway with transcoding support]) +fi +AM_CONDITIONAL(BUILD_MGCP_TRANSCODING, test "x$osmo_ac_mgcp_transcoding" = "xyes") +AC_SUBST(osmo_ac_mgcp_transcoding) + found_libgtp=yes PKG_CHECK_MODULES(LIBGTP, libgtp, , found_libgtp=no) diff --git a/openbsc/src/osmo-bsc_mgcp/Makefile.am b/openbsc/src/osmo-bsc_mgcp/Makefile.am index 0456cf1..a620e7a 100644 --- a/openbsc/src/osmo-bsc_mgcp/Makefile.am +++ b/openbsc/src/osmo-bsc_mgcp/Makefile.am @@ -1,10 +1,16 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) \ - $(LIBOSMOVTY_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) + $(LIBOSMOVTY_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) \ + $(LIBBCG729_CFLAGS) bin_PROGRAMS = osmo-bsc_mgcp osmo_bsc_mgcp_SOURCES = mgcp_main.c +if BUILD_MGCP_TRANSCODING + osmo_bsc_mgcp_SOURCES += mgcp_transcode.c +endif osmo_bsc_mgcp_LDADD = $(top_builddir)/src/libcommon/libcommon.a \ $(top_builddir)/src/libmgcp/libmgcp.a -lrt \ - $(LIBOSMOVTY_LIBS) $(LIBOSMOCORE_LIBS) + $(LIBOSMOVTY_LIBS) $(LIBOSMOCORE_LIBS) $(LIBBCG729_LIBS) + +noinst_HEADERS = g711common.h mgcp_transcode.h diff --git a/openbsc/src/osmo-bsc_mgcp/g711common.h b/openbsc/src/osmo-bsc_mgcp/g711common.h new file mode 100644 index 0000000..cb35fc6 --- /dev/null +++ b/openbsc/src/osmo-bsc_mgcp/g711common.h @@ -0,0 +1,187 @@ +/* + * PCM - A-Law conversion + * Copyright (c) 2000 by Abramo Bagnara + * + * Wrapper for linphone Codec class by Simon Morlat + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +static inline int val_seg(int val) +{ + int r = 0; + val >>= 7; /*7 = 4 + 3*/ + if (val & 0xf0) { + val >>= 4; + r += 4; + } + if (val & 0x0c) { + val >>= 2; + r += 2; + } + if (val & 0x02) + r += 1; + return r; +} + +/* + * s16_to_alaw() - Convert a 16-bit linear PCM value to 8-bit A-law + * + * s16_to_alaw() accepts an 16-bit integer and encodes it as A-law data. + * + * Linear Input Code Compressed Code + * ------------------------ --------------- + * 0000000wxyza 000wxyz + * 0000001wxyza 001wxyz + * 000001wxyzab 010wxyz + * 00001wxyzabc 011wxyz + * 0001wxyzabcd 100wxyz + * 001wxyzabcde 101wxyz + * 01wxyzabcdef 110wxyz + * 1wxyzabcdefg 111wxyz + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + * G711 is designed for 13 bits input signal, this function add extra shifting to take this into account. + */ + +static inline unsigned char s16_to_alaw(int pcm_val) +{ + int mask; + int seg; + unsigned char aval; + + if (pcm_val >= 0) { + mask = 0xD5; + } else { + mask = 0x55; + pcm_val = -pcm_val; + if (pcm_val > 0x7fff) + pcm_val = 0x7fff; + } + + if (pcm_val < 256) /*256 = 32 << 3*/ + aval = pcm_val >> 4; /*4 = 1 + 3*/ + else { + /* Convert the scaled magnitude to segment number. */ + seg = val_seg(pcm_val); + aval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f); + } + return aval ^ mask; +} + +/* + * alaw_to_s16() - Convert an A-law value to 16-bit linear PCM + * + */ +static inline int alaw_to_s16(unsigned char a_val) +{ + int t; + int seg; + + a_val ^= 0x55; + t = a_val & 0x7f; + if (t < 16) + t = (t << 4) + 8; + else { + seg = (t >> 4) & 0x07; + t = ((t & 0x0f) << 4) + 0x108; + t <<= seg -1; + } + return ((a_val & 0x80) ? t : -t); +} +/* + * s16_to_ulaw() - Convert a linear PCM value to u-law + * + * In order to simplify the encoding process, the original linear magnitude + * is biased by adding 33 which shifts the encoding range from (0 - 8158) to + * (33 - 8191). The result can be seen in the following encoding table: + * + * Biased Linear Input Code Compressed Code + * ------------------------ --------------- + * 00000001wxyza 000wxyz + * 0000001wxyzab 001wxyz + * 000001wxyzabc 010wxyz + * 00001wxyzabcd 011wxyz + * 0001wxyzabcde 100wxyz + * 001wxyzabcdef 101wxyz + * 01wxyzabcdefg 110wxyz + * 1wxyzabcdefgh 111wxyz + * + * Each biased linear code has a leading 1 which identifies the segment + * number. The value of the segment number is equal to 7 minus the number + * of leading 0's. The quantization interval is directly available as the + * four bits wxyz. * The trailing bits (a - h) are ignored. + * + * Ordinarily the complement of the resulting code word is used for + * transmission, and so the code word is complemented before it is returned. + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ + +static inline unsigned char s16_to_ulaw(int pcm_val) /* 2's complement (16-bit range) */ +{ + int mask; + int seg; + unsigned char uval; + + if (pcm_val < 0) { + pcm_val = 0x84 - pcm_val; + mask = 0x7f; + } else { + pcm_val += 0x84; + mask = 0xff; + } + if (pcm_val > 0x7fff) + pcm_val = 0x7fff; + + /* Convert the scaled magnitude to segment number. */ + seg = val_seg(pcm_val); + + /* + * Combine the sign, segment, quantization bits; + * and complement the code word. + */ + uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f); + return uval ^ mask; +} + +/* + * ulaw_to_s16() - Convert a u-law value to 16-bit linear PCM + * + * First, a biased linear code is derived from the code word. An unbiased + * output can then be obtained by subtracting 33 from the biased code. + * + * Note that this function expects to be passed the complement of the + * original code word. This is in keeping with ISDN conventions. + */ +static inline int ulaw_to_s16(unsigned char u_val) +{ + int t; + + /* Complement to obtain normal u-law value. */ + u_val = ~u_val; + + /* + * Extract and bias the quantization bits. Then + * shift up by the segment number and subtract out the bias. + */ + t = ((u_val & 0x0f) << 3) + 0x84; + t <<= (u_val & 0x70) >> 4; + + return ((u_val & 0x80) ? (0x84 - t) : (t - 0x84)); +} diff --git a/openbsc/src/osmo-bsc_mgcp/mgcp_main.c b/openbsc/src/osmo-bsc_mgcp/mgcp_main.c index 14ec221..6b72965 100644 --- a/openbsc/src/osmo-bsc_mgcp/mgcp_main.c +++ b/openbsc/src/osmo-bsc_mgcp/mgcp_main.c @@ -49,6 +49,10 @@ #include "../../bscconfig.h" +#ifdef BUILD_MGCP_TRANSCODING +#include "mgcp_transcode.h" +#endif + /* this is here for the vty... it will never be called */ void subscr_put() { abort(); } @@ -207,6 +211,12 @@ int main(int argc, char **argv) if (!cfg) return -1; +#ifdef BUILD_MGCP_TRANSCODING + cfg->setup_rtp_processing_cb = &mgcp_transcoding_setup; + cfg->rtp_processing_cb = &mgcp_transcoding_process_rtp; + cfg->get_net_downlink_format_cb = &mgcp_transcoding_net_downlink_format; +#endif + vty_info.copyright = openbsc_copyright; vty_init(&vty_info); logging_vty_add_cmds(&log_info); diff --git a/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c b/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c new file mode 100644 index 0000000..7247c88 --- /dev/null +++ b/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c @@ -0,0 +1,452 @@ +/* + * (C) 2014 by Sysmocom s.f.m.c. GmbH + * (C) 2014 by On-Waves + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include + +#include "bscconfig.h" + +#include "g711common.h" +#include +#ifdef HAVE_BCG729 +#include +#include +#endif + +#include +#include +#include + +#include + +enum audio_format { + AF_INVALID, + AF_S16, + AF_L16, + AF_GSM, + AF_G729, + AF_PCMA +}; + +struct mgcp_process_rtp_state { + /* decoding */ + enum audio_format src_fmt; + union { + gsm gsm_handle; +#ifdef HAVE_BCG729 + bcg729DecoderChannelContextStruct *g729_dec; +#endif + } src; + size_t src_frame_size; + size_t src_samples_per_frame; + + /* processing */ + + /* encoding */ + enum audio_format dst_fmt; + union { + gsm gsm_handle; +#ifdef HAVE_BCG729 + bcg729EncoderChannelContextStruct *g729_enc; +#endif + } dst; + size_t dst_frame_size; + size_t dst_samples_per_frame; +}; + +static enum audio_format get_audio_format(const struct mgcp_rtp_end *rtp_end) +{ + if (rtp_end->subtype_name) { + if (!strcmp("GSM", rtp_end->subtype_name)) + return AF_GSM; + if (!strcmp("PCMA", rtp_end->subtype_name)) + return AF_PCMA; +#ifdef HAVE_BCG729 + if (!strcmp("G729", rtp_end->subtype_name)) + return AF_G729; +#endif + if (!strcmp("L16", rtp_end->subtype_name)) + return AF_L16; + } + + switch (rtp_end->payload_type) { + case 3 /* GSM */: + return AF_GSM; + case 8 /* PCMA */: + return AF_PCMA; +#ifdef HAVE_BCG729 + case 18 /* G.729 */: + return AF_G729; +#endif + case 11 /* L16 */: + return AF_L16; + default: + return AF_INVALID; + } +} + +static void l16_encode(short *sample, unsigned char *buf, size_t n) +{ + for (; n > 0; --n, ++sample, buf += 2) { + buf[0] = sample[0] >> 8; + buf[1] = sample[0] & 0xff; + } +} + +static void l16_decode(unsigned char *buf, short *sample, size_t n) +{ + for (; n > 0; --n, ++sample, buf += 2) + sample[0] = ((short)buf[0] << 8) | buf[1]; +} + +static void alaw_encode(short *sample, unsigned char *buf, size_t n) +{ + for (; n > 0; --n) + *(buf++) = s16_to_alaw(*(sample++)); +} + +static void alaw_decode(unsigned char *buf, short *sample, size_t n) +{ + for (; n > 0; --n) + *(sample++) = alaw_to_s16(*(buf++)); +} + +static int processing_state_destructor(struct mgcp_process_rtp_state *state) +{ + switch (state->src_fmt) { + case AF_GSM: + if (state->dst.gsm_handle) + gsm_destroy(state->src.gsm_handle); + break; +#ifdef HAVE_BCG729 + case AF_G729: + if (state->src.g729_dec) + closeBcg729DecoderChannel(state->src.g729_dec); + break; +#endif + default: + break; + } + switch (state->dst_fmt) { + case AF_GSM: + if (state->dst.gsm_handle) + gsm_destroy(state->dst.gsm_handle); + break; +#ifdef HAVE_BCG729 + case AF_G729: + if (state->dst.g729_enc) + closeBcg729EncoderChannel(state->dst.g729_enc); + break; +#endif + default: + break; + } + return 0; +} + +int mgcp_transcoding_setup(struct mgcp_endpoint *endp, + struct mgcp_rtp_end *dst_end, + struct mgcp_rtp_end *src_end) +{ + struct mgcp_process_rtp_state *state = dst_end->rtp_process_data; + enum audio_format src_fmt, dst_fmt; + + /* cleanup first */ + if (state) { + talloc_free(state); + dst_end->rtp_process_data = NULL; + } + + if (!src_end) + return 0; + + src_fmt = get_audio_format(src_end); + dst_fmt = get_audio_format(dst_end); + + LOGP(DMGCP, LOGL_ERROR, + "Checking transcoding: %s (%d) -> %s (%d)\n", + src_end->subtype_name, src_end->payload_type, + dst_end->subtype_name, dst_end->payload_type); + + if (src_fmt == AF_INVALID || dst_fmt == AF_INVALID) { + if (!src_end->subtype_name || !dst_end->subtype_name) + /* Not enough info, do nothing */ + return 0; + + if (strcmp(src_end->subtype_name, dst_end->subtype_name) == 0) + /* Nothing to do */ + return 0; + + LOGP(DMGCP, LOGL_ERROR, + "Cannot transcode: %s codec not supported (%s -> %s).\n", + src_fmt != AF_INVALID ? "destination" : "source", + src_end->audio_name, dst_end->audio_name); + return -EINVAL; + } + + if (src_end->rate && dst_end->rate && src_end->rate != dst_end->rate) { + LOGP(DMGCP, LOGL_ERROR, + "Cannot transcode: rate conversion (%d -> %d) not supported.\n", + src_end->rate, dst_end->rate); + return -EINVAL; + } + + state = talloc_zero(endp->tcfg->cfg, struct mgcp_process_rtp_state); + talloc_set_destructor(state, processing_state_destructor); + dst_end->rtp_process_data = state; + + state->src_fmt = src_fmt; + + switch (state->src_fmt) { + case AF_L16: + case AF_S16: + state->src_frame_size = 80 * sizeof(short); + state->src_samples_per_frame = 80; + break; + case AF_GSM: + state->src_frame_size = sizeof(gsm_frame); + state->src_samples_per_frame = 160; + state->src.gsm_handle = gsm_create(); + if (!state->src.gsm_handle) { + LOGP(DMGCP, LOGL_ERROR, + "Failed to initialize GSM decoder.\n"); + return -EINVAL; + } + break; +#ifdef HAVE_BCG729 + case AF_G729: + state->src_frame_size = 10; + state->src_samples_per_frame = 80; + state->src.g729_dec = initBcg729DecoderChannel(); + if (!state->src.g729_dec) { + LOGP(DMGCP, LOGL_ERROR, + "Failed to initialize G.729 decoder.\n"); + return -EINVAL; + } + break; +#endif + case AF_PCMA: + state->src_frame_size = 80; + state->src_samples_per_frame = 80; + break; + default: + break; + } + + state->dst_fmt = dst_fmt; + + switch (state->dst_fmt) { + case AF_L16: + case AF_S16: + state->dst_frame_size = 80*sizeof(short); + state->dst_samples_per_frame = 80; + break; + case AF_GSM: + state->dst_frame_size = sizeof(gsm_frame); + state->dst_samples_per_frame = 160; + state->dst.gsm_handle = gsm_create(); + if (!state->dst.gsm_handle) { + LOGP(DMGCP, LOGL_ERROR, + "Failed to initialize GSM encoder.\n"); + return -EINVAL; + } + break; +#ifdef HAVE_BCG729 + case AF_G729: + state->dst_frame_size = 10; + state->dst_samples_per_frame = 80; + state->dst.g729_enc = initBcg729EncoderChannel(); + if (!state->dst.g729_enc) { + LOGP(DMGCP, LOGL_ERROR, + "Failed to initialize G.729 decoder.\n"); + return -EINVAL; + } + break; +#endif + case AF_PCMA: + state->dst_frame_size = 80; + state->dst_samples_per_frame = 80; + break; + default: + break; + } + + LOGP(DMGCP, LOGL_INFO, + "Initialized RTP processing on: 0x%x " + "conv: %d (%d, %d, %s) -> %d (%d, %d, %s)\n", + ENDPOINT_NUMBER(endp), + src_fmt, src_end->payload_type, src_end->rate, src_end->fmtp_extra, + dst_fmt, dst_end->payload_type, dst_end->rate, dst_end->fmtp_extra); + + return 0; +} + +void mgcp_transcoding_net_downlink_format(struct mgcp_endpoint *endp, + int *payload_type, + const char**audio_name, + const char**fmtp_extra) +{ + struct mgcp_process_rtp_state *state = endp->net_end.rtp_process_data; + if (!state || endp->net_end.payload_type < 0) { + *payload_type = endp->bts_end.payload_type; + *audio_name = endp->bts_end.audio_name; + *fmtp_extra = endp->bts_end.fmtp_extra; + return; + } + + *payload_type = endp->net_end.payload_type; + *fmtp_extra = endp->net_end.fmtp_extra; + *audio_name = endp->net_end.audio_name; +} + + +int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp, + struct mgcp_rtp_end *dst_end, + char *data, int *len, int buf_size) +{ + struct mgcp_process_rtp_state *state = dst_end->rtp_process_data; + size_t rtp_hdr_size = 12; + char *payload_data = data + rtp_hdr_size; + int payload_len = *len - rtp_hdr_size; + size_t sample_cnt = 0; + size_t sample_idx; + int16_t samples[10*160]; + uint8_t *src = (uint8_t *)payload_data; + uint8_t *dst = (uint8_t *)payload_data; + size_t nbytes = payload_len; + size_t frame_remainder; + + if (!state) + return 0; + + if (state->src_fmt == state->dst_fmt) + return 0; + + /* TODO: check payload type (-> G.711 comfort noise) */ + + /* Decode src into samples */ + while (nbytes >= state->src_frame_size) { + if (sample_cnt + state->src_samples_per_frame > ARRAY_SIZE(samples)) { + LOGP(DMGCP, LOGL_ERROR, + "Sample buffer too small: %d > %d.\n", + sample_cnt + state->src_samples_per_frame, + ARRAY_SIZE(samples)); + return -ENOSPC; + } + switch (state->src_fmt) { + case AF_GSM: + if (gsm_decode(state->src.gsm_handle, + (gsm_byte *)src, samples + sample_cnt) < 0) { + LOGP(DMGCP, LOGL_ERROR, + "Failed to decode GSM.\n"); + return -EINVAL; + } + break; +#ifdef HAVE_BCG729 + case AF_G729: + bcg729Decoder(state->src.g729_dec, src, 0, samples + sample_cnt); + break; +#endif + case AF_PCMA: + alaw_decode(src, samples + sample_cnt, + state->src_samples_per_frame); + break; + case AF_S16: + memmove(samples + sample_cnt, src, + state->src_frame_size); + break; + case AF_L16: + l16_decode(src, samples + sample_cnt, + state->src_samples_per_frame); + break; + default: + break; + } + src += state->src_frame_size; + nbytes -= state->src_frame_size; + sample_cnt += state->src_samples_per_frame; + } + + /* Add silence if necessary */ + frame_remainder = sample_cnt % state->dst_samples_per_frame; + if (frame_remainder) { + size_t silence = state->dst_samples_per_frame - frame_remainder; + if (sample_cnt + silence > ARRAY_SIZE(samples)) { + LOGP(DMGCP, LOGL_ERROR, + "Sample buffer too small for silence: %d > %d.\n", + sample_cnt + silence, + ARRAY_SIZE(samples)); + return -ENOSPC; + } + + while (silence > 0) { + samples[sample_cnt] = 0; + sample_cnt += 1; + silence -= 1; + } + } + + /* Encode samples into dst */ + sample_idx = 0; + nbytes = 0; + while (sample_idx + state->dst_samples_per_frame <= sample_cnt) { + if (nbytes + state->dst_frame_size > buf_size) { + LOGP(DMGCP, LOGL_ERROR, + "Encoding (RTP) buffer too small: %d > %d.\n", + nbytes + state->dst_frame_size, buf_size); + return -ENOSPC; + } + switch (state->dst_fmt) { + case AF_GSM: + gsm_encode(state->dst.gsm_handle, + samples + sample_idx, dst); + break; +#ifdef HAVE_BCG729 + case AF_G729: + bcg729Encoder(state->dst.g729_enc, + samples + sample_idx, dst); + break; +#endif + case AF_PCMA: + alaw_encode(samples + sample_idx, dst, + state->src_samples_per_frame); + break; + case AF_S16: + memmove(dst, samples + sample_idx, state->dst_frame_size); + break; + case AF_L16: + l16_encode(samples + sample_idx, dst, + state->src_samples_per_frame); + break; + default: + break; + } + dst += state->dst_frame_size; + nbytes += state->dst_frame_size; + sample_idx += state->dst_samples_per_frame; + } + + *len = rtp_hdr_size + nbytes; + /* Patch payload type */ + data[1] = (data[1] & 0x80) | (dst_end->payload_type & 0x7f); + + return 0; +} diff --git a/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.h b/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.h new file mode 100644 index 0000000..2dfb06a --- /dev/null +++ b/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.h @@ -0,0 +1,34 @@ +/* + * (C) 2014 by On-Waves + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +#ifndef OPENBSC_MGCP_TRANSCODE_H +#define OPENBSC_MGCP_TRANSCODE_H + +int mgcp_transcoding_setup(struct mgcp_endpoint *endp, + struct mgcp_rtp_end *dst_end, + struct mgcp_rtp_end *src_end); + +void mgcp_transcoding_net_downlink_format(struct mgcp_endpoint *endp, + int *payload_type, + const char**audio_name, + const char**fmtp_extra); + +int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp, + struct mgcp_rtp_end *dst_end, + char *data, int *len, int buf_size); +#endif /* OPENBSC_MGCP_TRANSCODE_H */ -- 1.7.9.5 From jerlbeck at sysmocom.de Thu May 15 08:29:14 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Thu, 15 May 2014 10:29:14 +0200 Subject: [PATCH 06/11] mgcp: Add CLI tool to test audio conversion In-Reply-To: <1400142559-26788-1-git-send-email-jerlbeck@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> <1400142559-26788-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1400142559-26788-6-git-send-email-jerlbeck@sysmocom.de> This tool uses mgcp_transcode.c to convert audio data from stdin to stdout. Sponsored-by: On-Waves ehf --- openbsc/contrib/testconv/Makefile | 17 ++++++ openbsc/contrib/testconv/testconv_main.c | 91 ++++++++++++++++++++++++++++ openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c | 13 ++++ openbsc/src/osmo-bsc_mgcp/mgcp_transcode.h | 2 + 4 files changed, 123 insertions(+) create mode 100644 openbsc/contrib/testconv/Makefile create mode 100644 openbsc/contrib/testconv/testconv_main.c diff --git a/openbsc/contrib/testconv/Makefile b/openbsc/contrib/testconv/Makefile new file mode 100644 index 0000000..90adecc --- /dev/null +++ b/openbsc/contrib/testconv/Makefile @@ -0,0 +1,17 @@ + +OBJS = testconv_main.o mgcp_transcode.o + +CC = gcc +CFLAGS = -O0 -ggdb -Wall +LDFLAGS = +CPPFLAGS = -I../.. -I../../include $(shell pkg-config --cflags libosmocore) $(shell pkg-config --cflags libbcg729) +LIBS = ../../src/libmgcp/libmgcp.a ../../src/libcommon/libcommon.a $(shell pkg-config --libs libosmocore) $(shell pkg-config --libs libbcg729) -lgsm -lrt + +testconv: $(OBJS) + $(CC) -o $@ $^ $(LDFLAGS) $(LIBS) + +testconv_main.o: testconv_main.c +mgcp_transcode.o: ../../src/osmo-bsc_mgcp/mgcp_transcode.c + +$(OBJS): + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< diff --git a/openbsc/contrib/testconv/testconv_main.c b/openbsc/contrib/testconv/testconv_main.c new file mode 100644 index 0000000..c2785f2 --- /dev/null +++ b/openbsc/contrib/testconv/testconv_main.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "bscconfig.h" +#ifndef BUILD_MGCP_TRANSCODING +#error "Requires MGCP transcoding enabled (see --enable-mgcp-transcoding)" +#endif + +#include "src/osmo-bsc_mgcp/mgcp_transcode.h" + +static int audio_name_to_type(const char *name) +{ + if (!strcasecmp(name, "gsm")) + return 3; +#ifdef HAVE_BCG729 + else if (!strcasecmp(name, "g729")) + return 18; +#endif + else if (!strcasecmp(name, "pcma")) + return 8; + else if (!strcasecmp(name, "l16")) + return 11; + return -1; +} + +int mgcp_get_trans_frame_size(void *state_, int nsamples, int dst); + +int main(int argc, char **argv) +{ + char buf[4096] = {0}; + int cc, rc; + struct mgcp_rtp_end dst_end = {0}; + struct mgcp_rtp_end src_end = {0}; + struct mgcp_trunk_config tcfg = {{0}}; + struct mgcp_endpoint endp = {0}; + struct mgcp_process_rtp_state *state; + int in_size; + + osmo_init_logging(&log_info); + + tcfg.endpoints = &endp; + tcfg.number_endpoints = 1; + endp.tcfg = &tcfg; + + if (argc <= 2) + errx(1, "Usage: {gsm|g729|pcma|l16} {gsm|g729|pcma|l16}"); + + if ((src_end.payload_type = audio_name_to_type(argv[1])) == -1) + errx(1, "invalid input format '%s'", argv[1]); + if ((dst_end.payload_type = audio_name_to_type(argv[2])) == -1) + errx(1, "invalid output format '%s'", argv[2]); + + rc = mgcp_transcoding_setup(&endp, &dst_end, &src_end); + if (rc < 0) + errx(1, "setup failed: %s", strerror(-rc)); + + state = dst_end.rtp_process_data; + OSMO_ASSERT(state != NULL); + + in_size = mgcp_transcoding_get_frame_size(state, 160, 0); + OSMO_ASSERT(sizeof(buf) >= in_size + 12); + + while ((cc = read(0, buf + 12, in_size))) { + if (cc != in_size) + err(1, "read"); + + cc += 12; /* include RTP header */ + + rc = mgcp_transcoding_process_rtp(&endp, &dst_end, + buf, &cc, sizeof(buf)); + if (rc < 0) + errx(1, "processing failed: %s", strerror(-rc)); + + cc -= 12; /* ignore RTP header */ + if (write(1, buf + 12, cc) != cc) + err(1, "write"); + } + return 0; +} + diff --git a/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c b/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c index 7247c88..67e7e52 100644 --- a/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c +++ b/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c @@ -72,6 +72,19 @@ struct mgcp_process_rtp_state { size_t dst_samples_per_frame; }; +int mgcp_transcoding_get_frame_size(void *state_, int nsamples, int dst) +{ + struct mgcp_process_rtp_state *state = state_; + if (dst) + return (nsamples >= 0 ? + nsamples / state->dst_samples_per_frame : + 1) * state->dst_frame_size; + else + return (nsamples >= 0 ? + nsamples / state->src_samples_per_frame : + 1) * state->src_frame_size; +} + static enum audio_format get_audio_format(const struct mgcp_rtp_end *rtp_end) { if (rtp_end->subtype_name) { diff --git a/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.h b/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.h index 2dfb06a..0961634 100644 --- a/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.h +++ b/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.h @@ -31,4 +31,6 @@ void mgcp_transcoding_net_downlink_format(struct mgcp_endpoint *endp, int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end, char *data, int *len, int buf_size); + +int mgcp_transcoding_get_frame_size(void *state_, int nsamples, int dst); #endif /* OPENBSC_MGCP_TRANSCODE_H */ -- 1.7.9.5 From jerlbeck at sysmocom.de Thu May 15 08:29:15 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Thu, 15 May 2014 10:29:15 +0200 Subject: [PATCH 07/11] mgcp: Add packet size (ptime) conversion In-Reply-To: <1400142559-26788-1-git-send-email-jerlbeck@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> <1400142559-26788-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1400142559-26788-7-git-send-email-jerlbeck@sysmocom.de> The current transcoder implemenation always does a 1:1 recoding concerning the duration of a packet. So RTP timestamps and sequence numbers are not modified. This is not sufficient in some cases, e.g. when the BTS does only allow for a single fixed ptime. This patch decouples encoding from decoding and moves the decoded samples to the state structure so that samples can be combined or drain according to the packaging of incoming and outgoing packets. This patch incorporates parts of Holger's experimental fixes in 0e669e05^..9eba68f9. Ticket: OW#1111 Sponsored-by: On-Waves ehf --- openbsc/contrib/testconv/testconv_main.c | 52 +++++-- openbsc/include/openbsc/mgcp.h | 5 +- openbsc/include/openbsc/mgcp_internal.h | 3 +- openbsc/src/libmgcp/mgcp_network.c | 30 +++- openbsc/src/libmgcp/mgcp_protocol.c | 15 +- openbsc/src/libmgcp/mgcp_vty.c | 22 +++ openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c | 232 +++++++++++++++++++--------- 7 files changed, 262 insertions(+), 97 deletions(-) diff --git a/openbsc/contrib/testconv/testconv_main.c b/openbsc/contrib/testconv/testconv_main.c index c2785f2..aee7304 100644 --- a/openbsc/contrib/testconv/testconv_main.c +++ b/openbsc/contrib/testconv/testconv_main.c @@ -38,10 +38,10 @@ int mgcp_get_trans_frame_size(void *state_, int nsamples, int dst); int main(int argc, char **argv) { - char buf[4096] = {0}; + char buf[4096] = {0x80, 0}; int cc, rc; - struct mgcp_rtp_end dst_end = {0}; - struct mgcp_rtp_end src_end = {0}; + struct mgcp_rtp_end *dst_end; + struct mgcp_rtp_end *src_end; struct mgcp_trunk_config tcfg = {{0}}; struct mgcp_endpoint endp = {0}; struct mgcp_process_rtp_state *state; @@ -52,39 +52,63 @@ int main(int argc, char **argv) tcfg.endpoints = &endp; tcfg.number_endpoints = 1; endp.tcfg = &tcfg; + mgcp_free_endp(&endp); + + dst_end = &endp.bts_end; + src_end = &endp.net_end; if (argc <= 2) errx(1, "Usage: {gsm|g729|pcma|l16} {gsm|g729|pcma|l16}"); - if ((src_end.payload_type = audio_name_to_type(argv[1])) == -1) + if ((src_end->payload_type = audio_name_to_type(argv[1])) == -1) errx(1, "invalid input format '%s'", argv[1]); - if ((dst_end.payload_type = audio_name_to_type(argv[2])) == -1) + if ((dst_end->payload_type = audio_name_to_type(argv[2])) == -1) errx(1, "invalid output format '%s'", argv[2]); - rc = mgcp_transcoding_setup(&endp, &dst_end, &src_end); + rc = mgcp_transcoding_setup(&endp, dst_end, src_end); if (rc < 0) errx(1, "setup failed: %s", strerror(-rc)); - state = dst_end.rtp_process_data; + state = dst_end->rtp_process_data; OSMO_ASSERT(state != NULL); in_size = mgcp_transcoding_get_frame_size(state, 160, 0); OSMO_ASSERT(sizeof(buf) >= in_size + 12); + buf[1] = src_end->payload_type; + *(uint16_t*)(buf+2) = htons(1); + *(uint32_t*)(buf+4) = htonl(0); + *(uint32_t*)(buf+8) = htonl(0xaabbccdd); + while ((cc = read(0, buf + 12, in_size))) { + int cont; + int len; + if (cc != in_size) err(1, "read"); cc += 12; /* include RTP header */ - rc = mgcp_transcoding_process_rtp(&endp, &dst_end, - buf, &cc, sizeof(buf)); - if (rc < 0) - errx(1, "processing failed: %s", strerror(-rc)); + len = cc; + + do { + cont = mgcp_transcoding_process_rtp(&endp, dst_end, + buf, &len, sizeof(buf)); + if (cont == -EAGAIN) { + fprintf(stderr, "Got EAGAIN\n"); + break; + } + + if (cont < 0) + errx(1, "processing failed: %s", strerror(-cont)); + + len -= 12; /* ignore RTP header */ + + if (write(1, buf + 12, len) != len) + err(1, "write"); - cc -= 12; /* ignore RTP header */ - if (write(1, buf + 12, cc) != cc) - err(1, "write"); + len = cont; + } while (len > 0); } return 0; } diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h index b595aba..eb64e32 100644 --- a/openbsc/include/openbsc/mgcp.h +++ b/openbsc/include/openbsc/mgcp.h @@ -87,7 +87,8 @@ typedef int (*mgcp_policy)(struct mgcp_trunk_config *cfg, int endpoint, int stat typedef int (*mgcp_reset)(struct mgcp_trunk_config *cfg); typedef int (*mgcp_rqnt)(struct mgcp_endpoint *endp, char tone); -typedef int (*mgcp_processing)(struct mgcp_rtp_end *dst_end, +typedef int (*mgcp_processing)(struct mgcp_endpoint *endp, + struct mgcp_rtp_end *dst_end, char *data, int *len, int buf_size); typedef int (*mgcp_processing_setup)(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end, @@ -181,6 +182,8 @@ struct mgcp_config { struct mgcp_port_range transcoder_ports; int endp_dscp; + int bts_force_ptime; + mgcp_change change_cb; mgcp_policy policy_cb; mgcp_reset reset_cb; diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h index e74b9fa..c7bc2a8 100644 --- a/openbsc/include/openbsc/mgcp_internal.h +++ b/openbsc/include/openbsc/mgcp_internal.h @@ -90,6 +90,7 @@ struct mgcp_rtp_end { char *audio_name; char *subtype_name; int output_enabled; + int force_output_ptime; /* RTP patching */ int force_constant_ssrc; /* -1: always, 0: don't, 1: once */ @@ -202,7 +203,7 @@ void mgcp_state_calc_loss(struct mgcp_rtp_state *s, struct mgcp_rtp_end *, uint32_t mgcp_state_calc_jitter(struct mgcp_rtp_state *); /* payload processing default functions */ -int mgcp_rtp_processing_default(struct mgcp_rtp_end *dst_end, +int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end, char *data, int *len, int buf_size); int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp, diff --git a/openbsc/src/libmgcp/mgcp_network.c b/openbsc/src/libmgcp/mgcp_network.c index dcbb97a..42f0381 100644 --- a/openbsc/src/libmgcp/mgcp_network.c +++ b/openbsc/src/libmgcp/mgcp_network.c @@ -348,7 +348,7 @@ static int align_rtp_timestamp_offset(struct mgcp_endpoint *endp, return timestamp_error; } -int mgcp_rtp_processing_default(struct mgcp_rtp_end *dst_end, +int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end, char *data, int *len, int buf_size) { return 0; @@ -622,12 +622,28 @@ static int mgcp_send(struct mgcp_endpoint *endp, int dest, int is_rtp, if (!rtp_end->output_enabled) rtp_end->dropped_packets += 1; else if (is_rtp) { - mgcp_patch_and_count(endp, rtp_state, rtp_end, addr, buf, rc); - endp->cfg->rtp_processing_cb(rtp_end, buf, &rc, RTP_BUF_SIZE); - forward_data(rtp_end->rtp.fd, &endp->taps[tap_idx], buf, rc); - return mgcp_udp_send(rtp_end->rtp.fd, - &rtp_end->addr, - rtp_end->rtp_port, buf, rc); + int cont; + int nbytes = 0; + int len = rc; + mgcp_patch_and_count(endp, rtp_state, rtp_end, addr, buf, len); + do { + cont = endp->cfg->rtp_processing_cb(endp, rtp_end, + buf, &len, RTP_BUF_SIZE); + if (cont < 0) + break; + + forward_data(rtp_end->rtp.fd, &endp->taps[tap_idx], + buf, len); + rc = mgcp_udp_send(rtp_end->rtp.fd, + &rtp_end->addr, + rtp_end->rtp_port, buf, len); + + if (rc <= 0) + return rc; + nbytes += rc; + len = cont; + } while (len > 0); + return nbytes; } else if (!tcfg->omit_rtcp) { return mgcp_udp_send(rtp_end->rtcp.fd, &rtp_end->addr, diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c index f0d94c8..a903e3c 100644 --- a/openbsc/src/libmgcp/mgcp_protocol.c +++ b/openbsc/src/libmgcp/mgcp_protocol.c @@ -604,6 +604,12 @@ static int set_audio_info(void *ctx, struct mgcp_rtp_end *rtp, rtp->channels = channels; rtp->subtype_name = talloc_strdup(ctx, audio_codec); rtp->audio_name = talloc_strdup(ctx, audio_name); + + if (!strcmp(audio_codec, "G729")) { + rtp->frame_duration_num = 10; + rtp->frame_duration_den = 1000; + } + if (channels != 1) LOGP(DMGCP, LOGL_NOTICE, "Channels != 1 in SDP: '%s'\n", audio_name); @@ -916,11 +922,16 @@ mgcp_header_done: set_audio_info(p->cfg, &endp->bts_end, tcfg->audio_payload, tcfg->audio_name); endp->bts_end.fmtp_extra = talloc_strdup(tcfg->endpoints, tcfg->audio_fmtp_extra); - if (have_sdp) { + if (have_sdp) parse_sdp_data(&endp->net_end, p); - setup_rtp_processing(endp); + + if (p->cfg->bts_force_ptime) { + endp->bts_end.packet_duration_ms = p->cfg->bts_force_ptime; + endp->bts_end.force_output_ptime = 1; } + setup_rtp_processing(endp); + /* policy CB */ if (p->cfg->policy_cb) { int rc; diff --git a/openbsc/src/libmgcp/mgcp_vty.c b/openbsc/src/libmgcp/mgcp_vty.c index 953d34b..f1afa95 100644 --- a/openbsc/src/libmgcp/mgcp_vty.c +++ b/openbsc/src/libmgcp/mgcp_vty.c @@ -362,6 +362,26 @@ ALIAS_DEPRECATED(cfg_mgcp_rtp_ip_dscp, cfg_mgcp_rtp_ip_tos_cmd, RTP_STR "Apply IP_TOS to the audio stream\n" "The DSCP value\n") +#define FORCE_PTIME_STR "Force a fixed ptime for packets sent to the BTS" +DEFUN(cfg_mgcp_rtp_force_ptime, + cfg_mgcp_rtp_force_ptime_cmd, + "rtp force-ptime (10|20|40)", + RTP_STR FORCE_PTIME_STR + "The required ptime (packet duration) in ms\n") +{ + g_cfg->bts_force_ptime = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_no_rtp_force_ptime, + cfg_mgcp_no_rtp_force_ptime_cmd, + "no rtp force-ptime", + NO_STR RTP_STR FORCE_PTIME_STR) +{ + g_cfg->bts_force_ptime = 0; + return CMD_SUCCESS; +} + DEFUN(cfg_mgcp_sdp_fmtp_extra, cfg_mgcp_sdp_fmtp_extra_cmd, "sdp audio fmtp-extra .NAME", @@ -1084,6 +1104,8 @@ int mgcp_vty_init(void) install_element(MGCP_NODE, &cfg_mgcp_rtp_transcoder_base_cmd); install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_dscp_cmd); install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_tos_cmd); + install_element(MGCP_NODE, &cfg_mgcp_rtp_force_ptime_cmd); + install_element(MGCP_NODE, &cfg_mgcp_no_rtp_force_ptime_cmd); install_element(MGCP_NODE, &cfg_mgcp_rtp_keepalive_cmd); install_element(MGCP_NODE, &cfg_mgcp_rtp_keepalive_once_cmd); install_element(MGCP_NODE, &cfg_mgcp_no_rtp_keepalive_cmd); diff --git a/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c b/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c index 67e7e52..edd3178 100644 --- a/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c +++ b/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c @@ -1,5 +1,4 @@ /* - * (C) 2014 by Sysmocom s.f.m.c. GmbH * (C) 2014 by On-Waves * All Rights Reserved * @@ -22,7 +21,8 @@ #include #include -#include "bscconfig.h" + +#include "../../bscconfig.h" #include "g711common.h" #include @@ -70,6 +70,14 @@ struct mgcp_process_rtp_state { } dst; size_t dst_frame_size; size_t dst_samples_per_frame; + int dst_packet_duration; + + int is_running; + uint16_t next_seq; + uint32_t next_time; + int16_t samples[10*160]; + size_t sample_cnt; + size_t sample_offs; }; int mgcp_transcoding_get_frame_size(void *state_, int nsamples, int dst) @@ -302,6 +310,9 @@ int mgcp_transcoding_setup(struct mgcp_endpoint *endp, break; } + if (dst_end->force_output_ptime) + state->dst_packet_duration = mgcp_rtp_packet_duration(endp, dst_end); + LOGP(DMGCP, LOGL_INFO, "Initialized RTP processing on: 0x%x " "conv: %d (%d, %d, %s) -> %d (%d, %d, %s)\n", @@ -330,44 +341,21 @@ void mgcp_transcoding_net_downlink_format(struct mgcp_endpoint *endp, *audio_name = endp->net_end.audio_name; } - -int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp, - struct mgcp_rtp_end *dst_end, - char *data, int *len, int buf_size) +static int decode_audio(struct mgcp_process_rtp_state *state, + uint8_t **src, size_t *nbytes) { - struct mgcp_process_rtp_state *state = dst_end->rtp_process_data; - size_t rtp_hdr_size = 12; - char *payload_data = data + rtp_hdr_size; - int payload_len = *len - rtp_hdr_size; - size_t sample_cnt = 0; - size_t sample_idx; - int16_t samples[10*160]; - uint8_t *src = (uint8_t *)payload_data; - uint8_t *dst = (uint8_t *)payload_data; - size_t nbytes = payload_len; - size_t frame_remainder; - - if (!state) - return 0; - - if (state->src_fmt == state->dst_fmt) - return 0; - - /* TODO: check payload type (-> G.711 comfort noise) */ - - /* Decode src into samples */ - while (nbytes >= state->src_frame_size) { - if (sample_cnt + state->src_samples_per_frame > ARRAY_SIZE(samples)) { + while (*nbytes >= state->src_frame_size) { + if (state->sample_cnt + state->src_samples_per_frame > ARRAY_SIZE(state->samples)) { LOGP(DMGCP, LOGL_ERROR, "Sample buffer too small: %d > %d.\n", - sample_cnt + state->src_samples_per_frame, - ARRAY_SIZE(samples)); + state->sample_cnt + state->src_samples_per_frame, + ARRAY_SIZE(state->samples)); return -ENOSPC; } switch (state->src_fmt) { case AF_GSM: if (gsm_decode(state->src.gsm_handle, - (gsm_byte *)src, samples + sample_cnt) < 0) { + (gsm_byte *)*src, state->samples + state->sample_cnt) < 0) { LOGP(DMGCP, LOGL_ERROR, "Failed to decode GSM.\n"); return -EINVAL; @@ -375,54 +363,44 @@ int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp, break; #ifdef HAVE_BCG729 case AF_G729: - bcg729Decoder(state->src.g729_dec, src, 0, samples + sample_cnt); + bcg729Decoder(state->src.g729_dec, *src, 0, state->samples + state->sample_cnt); break; #endif case AF_PCMA: - alaw_decode(src, samples + sample_cnt, + alaw_decode(*src, state->samples + state->sample_cnt, state->src_samples_per_frame); break; case AF_S16: - memmove(samples + sample_cnt, src, + memmove(state->samples + state->sample_cnt, *src, state->src_frame_size); break; case AF_L16: - l16_decode(src, samples + sample_cnt, + l16_decode(*src, state->samples + state->sample_cnt, state->src_samples_per_frame); break; default: break; } - src += state->src_frame_size; - nbytes -= state->src_frame_size; - sample_cnt += state->src_samples_per_frame; - } - - /* Add silence if necessary */ - frame_remainder = sample_cnt % state->dst_samples_per_frame; - if (frame_remainder) { - size_t silence = state->dst_samples_per_frame - frame_remainder; - if (sample_cnt + silence > ARRAY_SIZE(samples)) { - LOGP(DMGCP, LOGL_ERROR, - "Sample buffer too small for silence: %d > %d.\n", - sample_cnt + silence, - ARRAY_SIZE(samples)); - return -ENOSPC; - } - - while (silence > 0) { - samples[sample_cnt] = 0; - sample_cnt += 1; - silence -= 1; - } + *src += state->src_frame_size; + *nbytes -= state->src_frame_size; + state->sample_cnt += state->src_samples_per_frame; } + return 0; +} +static int encode_audio(struct mgcp_process_rtp_state *state, + uint8_t *dst, size_t buf_size, size_t max_samples) +{ + int nbytes = 0; + size_t nsamples = 0; /* Encode samples into dst */ - sample_idx = 0; - nbytes = 0; - while (sample_idx + state->dst_samples_per_frame <= sample_cnt) { + while (nsamples + state->dst_samples_per_frame <= max_samples) { if (nbytes + state->dst_frame_size > buf_size) { - LOGP(DMGCP, LOGL_ERROR, + if (nbytes > 0) + break; + + /* Not even one frame fits into the buffer */ + LOGP(DMGCP, LOGL_INFO, "Encoding (RTP) buffer too small: %d > %d.\n", nbytes + state->dst_frame_size, buf_size); return -ENOSPC; @@ -430,23 +408,24 @@ int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp, switch (state->dst_fmt) { case AF_GSM: gsm_encode(state->dst.gsm_handle, - samples + sample_idx, dst); + state->samples + state->sample_offs, dst); break; #ifdef HAVE_BCG729 case AF_G729: bcg729Encoder(state->dst.g729_enc, - samples + sample_idx, dst); + state->samples + state->sample_offs, dst); break; #endif case AF_PCMA: - alaw_encode(samples + sample_idx, dst, + alaw_encode(state->samples + state->sample_offs, dst, state->src_samples_per_frame); break; case AF_S16: - memmove(dst, samples + sample_idx, state->dst_frame_size); + memmove(dst, state->samples + state->sample_offs, + state->dst_frame_size); break; case AF_L16: - l16_encode(samples + sample_idx, dst, + l16_encode(state->samples + state->sample_offs, dst, state->src_samples_per_frame); break; default: @@ -454,12 +433,121 @@ int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp, } dst += state->dst_frame_size; nbytes += state->dst_frame_size; - sample_idx += state->dst_samples_per_frame; + state->sample_offs += state->dst_samples_per_frame; + nsamples += state->dst_samples_per_frame; } + state->sample_cnt -= nsamples; + return nbytes; +} - *len = rtp_hdr_size + nbytes; - /* Patch payload type */ - data[1] = (data[1] & 0x80) | (dst_end->payload_type & 0x7f); +int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp, + struct mgcp_rtp_end *dst_end, + char *data, int *len, int buf_size) +{ + struct mgcp_process_rtp_state *state = dst_end->rtp_process_data; + size_t rtp_hdr_size = 12; + char *payload_data = data + rtp_hdr_size; + int payload_len = *len - rtp_hdr_size; + // size_t sample_idx; + uint8_t *src = (uint8_t *)payload_data; + uint8_t *dst = (uint8_t *)payload_data; + size_t nbytes = payload_len; + // size_t frame_remainder; + size_t nsamples; + size_t max_samples; + uint32_t ts_no; + int rc; - return 0; + if (!state) + return 0; + + if (state->src_fmt == state->dst_fmt) { + if (!state->dst_packet_duration) + return 0; + + /* TODO: repackage without transcoding */ + } + + /* If the remaining samples do not fit into a fixed ptime, + * a) discard them, if the next packet is much later + * b) add silence and * send it, if the current packet is not + * yet too late + * c) append the sample data, if the timestamp matches exactly + */ + + /* TODO: check payload type (-> G.711 comfort noise) */ + + if (payload_len > 0) { + ts_no = ntohl(*(uint32_t*)(data+4)); + if (!state->is_running) + state->next_seq = ntohs(*(uint32_t*)(data+4)); + + state->is_running = 1; + + if (state->sample_cnt > 0) { + int32_t delta = ts_no - state->next_time; + /* TODO: check sequence? reordering? packet loss? */ + + if (delta > state->sample_cnt) + /* There is a time gap between the last packet + * and the current one. Just discard the + * partial data that is left in the buffer. + * TODO: This can be improved by adding silence + * instead if the delta is small enough. + */ + state->sample_cnt = 0; + else if (delta < 0) { + LOGP(DMGCP, LOGL_NOTICE, + "RTP time jumps backwards, delta = %d, " + "discarding buffered samples\n", + delta); + state->sample_cnt = 0; + state->sample_offs = 0; + return -EAGAIN; + } + + /* Make sure the samples start without offset */ + fprintf(stderr, "Moving %d samples to buffer start (offset %d)\n", state->sample_cnt, state->sample_offs); + if (state->sample_offs && state->sample_cnt) + memmove(&state->samples[0], + &state->samples[state->sample_offs], + state->sample_cnt * sizeof(state->samples[0])); + } + + state->sample_offs = 0; + + /* Append decoded audio to samples */ + decode_audio(state, &src, &nbytes); + + if (nbytes > 0) + LOGP(DMGCP, LOGL_NOTICE, + "Skipped audio frame in RTP packet: %d octets\n", + nbytes); + } else + ts_no = state->next_time; + + if (state->sample_cnt < state->dst_packet_duration) + return -EAGAIN; + + max_samples = + state->dst_packet_duration ? + state->dst_packet_duration : state->sample_cnt; + + nsamples = state->sample_cnt; + + rc = encode_audio(state, dst, buf_size, max_samples); + if (rc <= 0) + return rc; + + nsamples -= state->sample_cnt; + fprintf(stderr, "Wrote %d samples to buffer (offset %d)\n", nsamples, state->sample_offs); + + *len = rtp_hdr_size + rc; + *(uint16_t*)(data+2) = htonl(state->next_seq); + *(uint32_t*)(data+4) = htonl(ts_no); + + state->next_seq += 1; + state->next_time = ts_no + nsamples; + + return nsamples ? rtp_hdr_size : 0; } -- 1.7.9.5 From jerlbeck at sysmocom.de Thu May 15 08:29:16 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Thu, 15 May 2014 10:29:16 +0200 Subject: [PATCH 08/11] mgcp: Extend the CLI transcoding tool by ptime conversion In-Reply-To: <1400142559-26788-1-git-send-email-jerlbeck@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> <1400142559-26788-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1400142559-26788-8-git-send-email-jerlbeck@sysmocom.de> This modification allows it to set the number of samples per packet that is written to the output. Sponsored-by: On-Waves ehf --- openbsc/contrib/testconv/testconv_main.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/openbsc/contrib/testconv/testconv_main.c b/openbsc/contrib/testconv/testconv_main.c index aee7304..e74c686 100644 --- a/openbsc/contrib/testconv/testconv_main.c +++ b/openbsc/contrib/testconv/testconv_main.c @@ -46,6 +46,10 @@ int main(int argc, char **argv) struct mgcp_endpoint endp = {0}; struct mgcp_process_rtp_state *state; int in_size; + int in_samples = 160; + int out_samples = 0; + uint32_t ts = 0; + uint16_t seq = 0; osmo_init_logging(&log_info); @@ -58,12 +62,20 @@ int main(int argc, char **argv) src_end = &endp.net_end; if (argc <= 2) - errx(1, "Usage: {gsm|g729|pcma|l16} {gsm|g729|pcma|l16}"); + errx(1, "Usage: {gsm|g729|pcma|l16} {gsm|g729|pcma|l16} [SPP]"); if ((src_end->payload_type = audio_name_to_type(argv[1])) == -1) errx(1, "invalid input format '%s'", argv[1]); if ((dst_end->payload_type = audio_name_to_type(argv[2])) == -1) errx(1, "invalid output format '%s'", argv[2]); + if (argc > 3) + out_samples = atoi(argv[3]); + + if (out_samples) { + dst_end->frame_duration_den = dst_end->rate; + dst_end->frame_duration_num = out_samples; + dst_end->frames_per_packet = 1; + } rc = mgcp_transcoding_setup(&endp, dst_end, src_end); if (rc < 0) @@ -72,7 +84,7 @@ int main(int argc, char **argv) state = dst_end->rtp_process_data; OSMO_ASSERT(state != NULL); - in_size = mgcp_transcoding_get_frame_size(state, 160, 0); + in_size = mgcp_transcoding_get_frame_size(state, in_samples, 0); OSMO_ASSERT(sizeof(buf) >= in_size + 12); buf[1] = src_end->payload_type; @@ -87,13 +99,19 @@ int main(int argc, char **argv) if (cc != in_size) err(1, "read"); + *(uint16_t*)(buf+2) = htonl(seq); + *(uint32_t*)(buf+4) = htonl(ts); + + seq += 1; + ts += in_samples; + cc += 12; /* include RTP header */ len = cc; do { cont = mgcp_transcoding_process_rtp(&endp, dst_end, - buf, &len, sizeof(buf)); + buf, &len, sizeof(buf)); if (cont == -EAGAIN) { fprintf(stderr, "Got EAGAIN\n"); break; -- 1.7.9.5 From jerlbeck at sysmocom.de Thu May 15 08:29:17 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Thu, 15 May 2014 10:29:17 +0200 Subject: [PATCH 09/11] mgcp/test: Add test cases for transcoding and repacking In-Reply-To: <1400142559-26788-1-git-send-email-jerlbeck@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> <1400142559-26788-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1400142559-26788-9-git-send-email-jerlbeck@sysmocom.de> This patch adds test cases for transcoding and repacking. Sponsored-by: On-Waves ehf --- openbsc/tests/atlocal.in | 1 + openbsc/tests/mgcp/Makefile.am | 19 +- openbsc/tests/mgcp/mgcp_transcoding_test.c | 377 +++++++++++++++++++ openbsc/tests/mgcp/mgcp_transcoding_test.ok | 534 +++++++++++++++++++++++++++ openbsc/tests/testsuite.at | 7 + 5 files changed, 935 insertions(+), 3 deletions(-) create mode 100644 openbsc/tests/mgcp/mgcp_transcoding_test.c create mode 100644 openbsc/tests/mgcp/mgcp_transcoding_test.ok diff --git a/openbsc/tests/atlocal.in b/openbsc/tests/atlocal.in index 4635113..542a78e 100644 --- a/openbsc/tests/atlocal.in +++ b/openbsc/tests/atlocal.in @@ -1,3 +1,4 @@ enable_nat_test='@osmo_ac_build_nat@' enable_smpp_test='@osmo_ac_build_smpp@' enable_bsc_test='@osmo_ac_build_bsc@' +enable_mgcp_transcoding_test='@osmo_ac_mgcp_transcoding@' diff --git a/openbsc/tests/mgcp/Makefile.am b/openbsc/tests/mgcp/Makefile.am index 71bf8c0..81f28ae 100644 --- a/openbsc/tests/mgcp/Makefile.am +++ b/openbsc/tests/mgcp/Makefile.am @@ -1,11 +1,15 @@ -AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOSCCP_CFLAGS) $(COVERAGE_CFLAGS) +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_srcdir) +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOSCCP_CFLAGS) $(COVERAGE_CFLAGS) $(LIBBCG729_CFLAGS) AM_LDFLAGS = $(COVERAGE_LDFLAGS) -EXTRA_DIST = mgcp_test.ok +EXTRA_DIST = mgcp_test.ok mgcp_transcoding_test.ok noinst_PROGRAMS = mgcp_test +if BUILD_MGCP_TRANSCODING +noinst_PROGRAMS += mgcp_transcoding_test +endif + mgcp_test_SOURCES = mgcp_test.c mgcp_test_LDADD = $(top_builddir)/src/libbsc/libbsc.a \ @@ -13,3 +17,12 @@ mgcp_test_LDADD = $(top_builddir)/src/libbsc/libbsc.a \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOCORE_LIBS) -lrt -lm $(LIBOSMOSCCP_LIBS) $(LIBOSMOVTY_LIBS) \ $(LIBRARY_DL) + +mgcp_transcoding_test_SOURCES = mgcp_transcoding_test.c $(top_builddir)/src/osmo-bsc_mgcp/mgcp_transcode.c + +mgcp_transcoding_test_LDADD = \ + $(top_builddir)/src/libbsc/libbsc.a \ + $(top_builddir)/src/libmgcp/libmgcp.a \ + $(top_builddir)/src/libcommon/libcommon.a \ + $(LIBOSMOCORE_LIBS) $(LIBBCG729_LIBS) -lrt -lm $(LIBOSMOSCCP_LIBS) $(LIBOSMOVTY_LIBS) \ + $(LIBRARY_DL) diff --git a/openbsc/tests/mgcp/mgcp_transcoding_test.c b/openbsc/tests/mgcp/mgcp_transcoding_test.c new file mode 100644 index 0000000..e5da138 --- /dev/null +++ b/openbsc/tests/mgcp/mgcp_transcoding_test.c @@ -0,0 +1,377 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "bscconfig.h" +#ifndef BUILD_MGCP_TRANSCODING +#error "Requires MGCP transcoding enabled (see --enable-mgcp-transcoding)" +#endif + +#include "src/osmo-bsc_mgcp/mgcp_transcode.h" + +uint8_t *audio_frame_l16[] = { +}; + +struct rtp_packets { + float t; + int len; + char *data; +}; + +struct rtp_packets audio_packets_l16[] = { + /* RTP: SeqNo=1, TS=160 */ + {0.020000, 332, + "\x80\x0B\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED" + }, +}; + +struct rtp_packets audio_packets_gsm[] = { + /* RTP: SeqNo=1, TS=160 */ + {0.020000, 45, + "\x80\x03\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44" + "\xD4\x7C\xE3\xE9\x62\x50\x39\xF0\xF8\xB4\x68\xEA\x6C\x0E\x81\x1B" + "\x56\x2A\xD5\xBC\x69\x9C\xD1\xF0\x66\x7A\xEC\x49\x7A\x33\x3D\x0A" + "\xDE" + }, +}; + +struct rtp_packets audio_packets_gsm_invalid_size[] = { + /* RTP: SeqNo=1, TS=160 */ + {0.020000, 41, + "\x80\x03\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44" + "\xD4\x7C\xE3\xE9\x62\x50\x39\xF0\xF8\xB4\x68\xEA\x6C\x0E\x81\x1B" + "\x56\x2A\xD5\xBC\x69\x9C\xD1\xF0\x66\x7A\xEC\x49\x7A\x33\x3D\x0A" + "\xDE" + }, +}; + +struct rtp_packets audio_packets_gsm_invalid_data[] = { + /* RTP: SeqNo=1, TS=160 */ + {0.020000, 45, + "\x80\x03\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44" + "\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE" + "\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE" + "\xEE" + }, +}; + +struct rtp_packets audio_packets_gsm_invalid_ptype[] = { + /* RTP: SeqNo=1, TS=160 */ + {0.020000, 45, + "\x80\x08\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44" + "\xD4\x7C\xE3\xE9\x62\x50\x39\xF0\xF8\xB4\x68\xEA\x6C\x0E\x81\x1B" + "\x56\x2A\xD5\xBC\x69\x9C\xD1\xF0\x66\x7A\xEC\x49\x7A\x33\x3D\x0A" + "\xDE" + }, +}; + +struct rtp_packets audio_packets_g729[] = { + /* RTP: SeqNo=1, TS=160 */ + {0.020000, 32, + "\x80\x12\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44" + "\xAF\xC2\x81\x40\x00\xFA\xCE\xA4\x21\x7C\xC5\xC3\x4F\xA5\x98\xF5" + "\xB2\x95\xC4\xAD" + }, +}; + +struct rtp_packets audio_packets_pcma[] = { + /* RTP: SeqNo=1, TS=160 */ + {0.020000, 172, + "\x80\x08\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44" + "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25" + "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25" + "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25" + "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25" + "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25" + "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25" + "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25" + "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25" + "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25" + "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25" + }, +}; + + + +static int audio_name_to_type(const char *name) +{ + if (!strcasecmp(name, "gsm")) + return 3; +#ifdef HAVE_BCG729 + else if (!strcasecmp(name, "g729")) + return 18; +#endif + else if (!strcasecmp(name, "pcma")) + return 8; + else if (!strcasecmp(name, "l16")) + return 11; + return -1; +} + +int mgcp_get_trans_frame_size(void *state_, int nsamples, int dst); + +static int transcode_test(const char *srcfmt, const char *dstfmt, + uint8_t *src_pkts, size_t src_pkt_size) +{ + char buf[4096] = {0x80, 0}; + int rc; + struct mgcp_rtp_end *dst_end; + struct mgcp_rtp_end *src_end; + struct mgcp_trunk_config tcfg = {{0}}; + struct mgcp_endpoint endp = {0}; + struct mgcp_process_rtp_state *state; + int in_size; + int in_samples = 160; + int len, cont; + + printf("== Transcoding test ==\n"); + printf("converting %s -> %s\n", srcfmt, dstfmt); + + tcfg.endpoints = &endp; + tcfg.number_endpoints = 1; + endp.tcfg = &tcfg; + mgcp_free_endp(&endp); + + dst_end = &endp.bts_end; + src_end = &endp.net_end; + + src_end->payload_type = audio_name_to_type(srcfmt); + dst_end->payload_type = audio_name_to_type(dstfmt); + + rc = mgcp_transcoding_setup(&endp, dst_end, src_end); + if (rc < 0) + errx(1, "setup failed: %s", strerror(-rc)); + + state = dst_end->rtp_process_data; + OSMO_ASSERT(state != NULL); + + in_size = mgcp_transcoding_get_frame_size(state, in_samples, 0); + OSMO_ASSERT(sizeof(buf) >= in_size + 12); + + memcpy(buf, src_pkts, src_pkt_size); + + len = src_pkt_size; + + cont = mgcp_transcoding_process_rtp(&endp, dst_end, + buf, &len, sizeof(buf)); + if (cont < 0) + errx(1, "processing failed: %s", strerror(-cont)); + + if (len < 24) { + printf("encoded: %s\n", osmo_hexdump((unsigned char *)buf, len)); + } else { + const char *str = osmo_hexdump((unsigned char *)buf, len); + int i = 0; + const int prefix = 4; + const int cutlen = 48; + int nchars = 0; + + printf("encoded:\n"); + do { + nchars = printf("%*s%-.*s", prefix, "", cutlen, str + i); + i += nchars - prefix; + printf("\n"); + } while (nchars - prefix >= cutlen); + } + return 0; +} + +static int test_repacking(int in_samples, int out_samples, int no_transcode) +{ + char buf[4096] = {0x80, 0}; + int cc, rc; + struct mgcp_rtp_end *dst_end; + struct mgcp_rtp_end *src_end; + struct mgcp_config *cfg; + struct mgcp_trunk_config tcfg = {{0}}; + struct mgcp_endpoint endp = {0}; + struct mgcp_process_rtp_state *state; + int in_cnt; + int out_size; + int in_size; + uint32_t ts = 0; + uint16_t seq = 0; + const char *srcfmt = "pcma"; + const char *dstfmt = no_transcode ? "pcma" : "l16"; + + cfg = mgcp_config_alloc(); + + tcfg.endpoints = &endp; + tcfg.number_endpoints = 1; + tcfg.cfg = cfg; + endp.tcfg = &tcfg; + endp.cfg = cfg; + mgcp_free_endp(&endp); + + dst_end = &endp.bts_end; + src_end = &endp.net_end; + + printf("== Transcoding test ==\n"); + printf("converting %s -> %s\n", srcfmt, dstfmt); + + src_end->payload_type = audio_name_to_type(srcfmt); + dst_end->payload_type = audio_name_to_type(dstfmt); + + if (out_samples) { + dst_end->frame_duration_den = dst_end->rate; + dst_end->frame_duration_num = out_samples; + dst_end->frames_per_packet = 1; + dst_end->force_output_ptime = 1; + } + + rc = mgcp_transcoding_setup(&endp, dst_end, src_end); + if (rc < 0) + errx(1, "setup failed: %s", strerror(-rc)); + + state = dst_end->rtp_process_data; + OSMO_ASSERT(state != NULL); + + in_size = mgcp_transcoding_get_frame_size(state, in_samples, 0); + OSMO_ASSERT(sizeof(buf) >= in_size + 12); + + out_size = mgcp_transcoding_get_frame_size(state, -1, 1); + OSMO_ASSERT(sizeof(buf) >= out_size + 12); + + buf[1] = src_end->payload_type; + *(uint16_t*)(buf+2) = htons(1); + *(uint32_t*)(buf+4) = htonl(0); + *(uint32_t*)(buf+8) = htonl(0xaabbccdd); + + for (in_cnt = 0; in_cnt < 16; in_cnt++) { + int cont; + int len; + + /* fake PCMA data */ + printf("generating %d %s input samples\n", in_samples, srcfmt); + for (cc = 0; cc < in_samples; cc++) + buf[12+cc] = cc; + + *(uint16_t*)(buf+2) = htonl(seq); + *(uint32_t*)(buf+4) = htonl(ts); + + seq += 1; + ts += in_samples; + + cc += 12; /* include RTP header */ + + len = cc; + + do { + cont = mgcp_transcoding_process_rtp(&endp, dst_end, + buf, &len, sizeof(buf)); + if (cont == -EAGAIN) { + fprintf(stderr, "Got EAGAIN\n"); + break; + } + + if (cont < 0) + errx(1, "processing failed: %s", strerror(-cont)); + + len -= 12; /* ignore RTP header */ + + printf("got %d %s output frames (%d octets)\n", + len / out_size, dstfmt, len); + + len = cont; + } while (len > 0); + } + return 0; +} + +int main(int argc, char **argv) +{ + osmo_init_logging(&log_info); + + printf("=== Transcoding Good Cases ===\n"); + + transcode_test("l16", "l16", + (uint8_t *)audio_packets_l16[0].data, + audio_packets_l16[0].len); + transcode_test("l16", "gsm", + (uint8_t *)audio_packets_l16[0].data, + audio_packets_l16[0].len); + transcode_test("l16", "pcma", + (uint8_t *)audio_packets_l16[0].data, + audio_packets_l16[0].len); + transcode_test("gsm", "l16", + (uint8_t *)audio_packets_gsm[0].data, + audio_packets_gsm[0].len); + transcode_test("gsm", "gsm", + (uint8_t *)audio_packets_gsm[0].data, + audio_packets_gsm[0].len); + transcode_test("gsm", "pcma", + (uint8_t *)audio_packets_gsm[0].data, + audio_packets_gsm[0].len); + transcode_test("pcma", "l16", + (uint8_t *)audio_packets_pcma[0].data, + audio_packets_pcma[0].len); + transcode_test("pcma", "gsm", + (uint8_t *)audio_packets_pcma[0].data, + audio_packets_pcma[0].len); + transcode_test("pcma", "pcma", + (uint8_t *)audio_packets_pcma[0].data, + audio_packets_pcma[0].len); + + printf("=== Transcoding Bad Cases ===\n"); + + printf("Invalid size:\n"); + transcode_test("gsm", "pcma", + (uint8_t *)audio_packets_gsm_invalid_size[0].data, + audio_packets_gsm_invalid_size[0].len); + + printf("Invalid data:\n"); + transcode_test("gsm", "pcma", + (uint8_t *)audio_packets_gsm_invalid_data[0].data, + audio_packets_gsm_invalid_data[0].len); + + printf("Invalid payload type:\n"); + transcode_test("gsm", "pcma", + (uint8_t *)audio_packets_gsm_invalid_ptype[0].data, + audio_packets_gsm_invalid_ptype[0].len); + + printf("=== Repacking ===\n"); + + test_repacking(160, 160, 0); + test_repacking(160, 160, 1); + test_repacking(160, 80, 0); + test_repacking(160, 80, 1); + test_repacking(160, 320, 0); + test_repacking(160, 320, 1); + test_repacking(160, 240, 0); + test_repacking(160, 240, 1); + test_repacking(160, 100, 0); + test_repacking(160, 100, 1); + + return 0; +} + diff --git a/openbsc/tests/mgcp/mgcp_transcoding_test.ok b/openbsc/tests/mgcp/mgcp_transcoding_test.ok new file mode 100644 index 0000000..189d079 --- /dev/null +++ b/openbsc/tests/mgcp/mgcp_transcoding_test.ok @@ -0,0 +1,534 @@ +=== Transcoding Good Cases === +== Transcoding test == +converting l16 -> l16 +encoded: + 80 0b 00 01 00 00 00 a0 11 22 33 44 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed 00 00 40 13 + 5a 9e 40 13 00 00 bf ed a5 62 bf ed +== Transcoding test == +converting l16 -> gsm +encoded: + 80 0b 00 00 00 00 00 a0 11 22 33 44 d4 7c e3 e9 + 62 50 39 f0 f8 b4 68 ea 6c 0e 81 1b 56 2a d5 bc + 69 9c d1 f0 66 7a ec 49 7a 33 3d 0a de +== Transcoding test == +converting l16 -> pcma +encoded: + 80 0b 00 00 00 00 00 a0 11 22 33 44 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 +== Transcoding test == +converting gsm -> l16 +encoded: + 80 03 00 00 00 00 00 a0 11 22 33 44 00 00 54 00 + 59 f0 34 20 c4 c8 b9 f8 e2 18 f1 e8 f2 28 f0 e0 + 46 08 4f 80 2c a0 a9 c8 80 00 c0 58 3f 80 63 c0 + 24 b8 fa b8 f6 88 0b a0 c8 70 a8 b0 c8 c0 3b a8 + 66 a0 2e 38 d1 f8 98 98 aa 18 e8 30 26 a0 37 40 + 37 e8 17 00 ee 50 b7 80 b1 88 de 28 18 40 45 b0 + 4f 48 21 d8 df 78 ae 68 ab 98 d6 b8 18 18 48 90 + 4e 70 27 40 e8 10 b5 b0 ac 80 d4 60 14 50 48 48 + 50 10 2a 00 ec 08 ba 00 af 58 d1 c0 10 60 45 c8 + 54 10 30 78 f1 a8 bb 18 ad 48 ce 30 0a e8 3f 30 + 4f 10 32 18 f6 18 bf 20 ac 30 cd 80 0b d0 43 d8 + 55 e0 34 a0 f5 78 bc 98 ad 98 cd c8 0a 80 40 58 + 51 c0 35 40 f9 60 c1 68 ac c8 cb 38 08 00 40 98 + 51 e0 34 d8 fa 28 c2 f0 ae 40 c7 70 02 d0 3c a8 + 54 78 38 a0 fc 68 c2 08 ad 50 c7 78 01 60 39 c0 + 51 38 3a e8 00 e8 c6 38 ab d8 c4 00 fe 08 39 18 + 50 30 39 50 01 d8 ca 70 b1 80 c4 c8 fc 58 36 40 + 51 d8 3b 08 02 80 c8 58 b0 60 c5 a8 fb d0 33 e8 + 4e 80 3c e0 06 10 cb 90 ae 48 c2 60 f9 58 34 08 + 4d a0 3a a8 06 48 cf 80 b4 60 c3 e8 f7 90 30 18 + 4d a0 3b 98 07 90 cf 18 b4 68 c4 88 +== Transcoding test == +converting gsm -> gsm +encoded: + 80 03 00 01 00 00 00 a0 11 22 33 44 d4 7c e3 e9 + 62 50 39 f0 f8 b4 68 ea 6c 0e 81 1b 56 2a d5 bc + 69 9c d1 f0 66 7a ec 49 7a 33 3d 0a de +== Transcoding test == +converting gsm -> pcma +encoded: + 80 03 00 00 00 00 00 a0 11 22 33 44 d5 a0 a3 bf + 38 24 08 19 1e 1b a4 a6 b3 20 2a 3a ba ad b7 60 + 17 92 3e 20 3e b8 ac b2 32 2c 20 02 b6 be be 82 + 04 27 26 35 8d a4 a6 b5 35 21 20 31 8d a7 a6 b6 + 02 27 21 30 81 a7 a1 b0 06 24 21 32 85 a4 a0 bd + 19 24 21 3d 90 ba a6 bc 16 25 21 3c 92 a5 a0 bf + 10 25 21 3c 90 a5 a1 bf 6f 3a 21 3f 95 a5 a1 bf + 62 3b 21 39 f3 bb a0 b9 79 3b 21 39 c3 b9 a1 b8 + db 39 20 3b 4a b9 a1 b9 c8 3f 26 38 78 be a1 b8 + f1 3e 26 38 65 bc a6 bb ed 3f 21 3b 6f bf a6 b8 + ec 3d 27 3b 15 bd a6 b8 eb 3d 27 38 +== Transcoding test == +converting pcma -> l16 +encoded: + 80 08 00 00 00 00 00 a0 11 22 33 44 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 00 08 42 00 + 5a 00 42 00 00 08 be 00 a6 00 be 00 +== Transcoding test == +converting pcma -> gsm +encoded: + 80 08 00 00 00 00 00 a0 11 22 33 44 d4 b9 f4 5d + d9 50 5a e1 a0 cd 76 ea 52 0e 87 53 ad d4 ea a2 + 0a 63 ca e9 60 79 e2 2a 25 d2 c0 f3 39 +== Transcoding test == +converting pcma -> pcma +encoded: + 80 08 00 01 00 00 00 a0 11 22 33 44 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 d5 a5 a3 a5 + d5 25 23 25 d5 a5 a3 a5 d5 25 23 25 +=== Transcoding Bad Cases === +Invalid size: +== Transcoding test == +converting gsm -> pcma +encoded: + 80 03 00 01 00 00 00 a0 11 22 33 44 d4 7c e3 e9 + 62 50 39 f0 f8 b4 68 ea 6c 0e 81 1b 56 2a d5 bc + 69 9c d1 f0 66 7a ec 49 7a +Invalid data: +== Transcoding test == +converting gsm -> pcma +encoded: + 80 03 00 01 00 00 00 a0 11 22 33 44 ee ee ee ee + ee ee ee ee ee ee ee ee ee ee ee ee ee ee ee ee + ee ee ee ee ee ee ee ee ee ee ee ee ee +Invalid payload type: +== Transcoding test == +converting gsm -> pcma +encoded: + 80 08 00 00 00 00 00 a0 11 22 33 44 d5 a0 a3 bf + 38 24 08 19 1e 1b a4 a6 b3 20 2a 3a ba ad b7 60 + 17 92 3e 20 3e b8 ac b2 32 2c 20 02 b6 be be 82 + 04 27 26 35 8d a4 a6 b5 35 21 20 31 8d a7 a6 b6 + 02 27 21 30 81 a7 a1 b0 06 24 21 32 85 a4 a0 bd + 19 24 21 3d 90 ba a6 bc 16 25 21 3c 92 a5 a0 bf + 10 25 21 3c 90 a5 a1 bf 6f 3a 21 3f 95 a5 a1 bf + 62 3b 21 39 f3 bb a0 b9 79 3b 21 39 c3 b9 a1 b8 + db 39 20 3b 4a b9 a1 b9 c8 3f 26 38 78 be a1 b8 + f1 3e 26 38 65 bc a6 bb ed 3f 21 3b 6f bf a6 b8 + ec 3d 27 3b 15 bd a6 b8 eb 3d 27 38 +=== Repacking === +== Transcoding test == +converting pcma -> l16 +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +generating 160 pcma input samples +got 2 l16 output frames (320 octets) +== Transcoding test == +converting pcma -> pcma +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +generating 160 pcma input samples +got 2 pcma output frames (160 octets) +== Transcoding test == +converting pcma -> l16 +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +== Transcoding test == +converting pcma -> pcma +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +== Transcoding test == +converting pcma -> l16 +generating 160 pcma input samples +generating 160 pcma input samples +got 4 l16 output frames (640 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 4 l16 output frames (640 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 4 l16 output frames (640 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 4 l16 output frames (640 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 4 l16 output frames (640 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 4 l16 output frames (640 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 4 l16 output frames (640 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 4 l16 output frames (640 octets) +== Transcoding test == +converting pcma -> pcma +generating 160 pcma input samples +generating 160 pcma input samples +got 4 pcma output frames (320 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 4 pcma output frames (320 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 4 pcma output frames (320 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 4 pcma output frames (320 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 4 pcma output frames (320 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 4 pcma output frames (320 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 4 pcma output frames (320 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 4 pcma output frames (320 octets) +== Transcoding test == +converting pcma -> l16 +generating 160 pcma input samples +generating 160 pcma input samples +got 3 l16 output frames (480 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 3 l16 output frames (480 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 3 l16 output frames (480 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 3 l16 output frames (480 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 3 l16 output frames (480 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 3 l16 output frames (480 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 3 l16 output frames (480 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 3 l16 output frames (480 octets) +== Transcoding test == +converting pcma -> pcma +generating 160 pcma input samples +generating 160 pcma input samples +got 3 pcma output frames (240 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 3 pcma output frames (240 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 3 pcma output frames (240 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 3 pcma output frames (240 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 3 pcma output frames (240 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 3 pcma output frames (240 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 3 pcma output frames (240 octets) +generating 160 pcma input samples +generating 160 pcma input samples +got 3 pcma output frames (240 octets) +== Transcoding test == +converting pcma -> l16 +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +generating 160 pcma input samples +got 1 l16 output frames (160 octets) +got 1 l16 output frames (160 octets) +== Transcoding test == +converting pcma -> pcma +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) +generating 160 pcma input samples +got 1 pcma output frames (80 octets) +got 1 pcma output frames (80 octets) diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 4465b25..57310d6 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -27,6 +27,13 @@ cat $abs_srcdir/mgcp/mgcp_test.ok > expout AT_CHECK([$abs_top_builddir/tests/mgcp/mgcp_test], [], [expout], [ignore]) AT_CLEANUP +AT_SETUP([mgcp-trans]) +AT_KEYWORDS([mgcp-trans]) +AT_CHECK([test "$enable_mgcp_transcoding_test" == yes || exit 77]) +cat $abs_srcdir/mgcp/mgcp_transcoding_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/mgcp/mgcp_transcoding_test], [], [expout], [ignore]) +AT_CLEANUP + AT_SETUP([gprs]) AT_KEYWORDS([gprs]) cat $abs_srcdir/gprs/gprs_test.ok > expout -- 1.7.9.5 From jerlbeck at sysmocom.de Thu May 15 08:29:18 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Thu, 15 May 2014 10:29:18 +0200 Subject: [PATCH 10/11] mgcp: Move transcoding to libmgcp In-Reply-To: <1400142559-26788-1-git-send-email-jerlbeck@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> <1400142559-26788-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1400142559-26788-10-git-send-email-jerlbeck@sysmocom.de> This patch moves the files relevant to transcoding from src/osmo-bsc_mgcp to src/libmgcp and src/include/openbsc. Makefiles and include directives are being updated accordingly. Sponsored-by: On-Waves ehf --- openbsc/contrib/testconv/Makefile | 3 +-- openbsc/contrib/testconv/testconv_main.c | 2 +- openbsc/include/openbsc/Makefile.am | 3 ++- .../openbsc}/mgcp_transcode.h | 0 openbsc/src/libmgcp/Makefile.am | 12 ++++++++++-- .../src/{osmo-bsc_mgcp => libmgcp}/g711common.h | 0 .../{osmo-bsc_mgcp => libmgcp}/mgcp_transcode.c | 0 openbsc/src/osmo-bsc_mgcp/Makefile.am | 9 ++------- openbsc/src/osmo-bsc_mgcp/mgcp_main.c | 2 +- openbsc/tests/mgcp/Makefile.am | 2 +- openbsc/tests/mgcp/mgcp_transcoding_test.c | 2 +- 11 files changed, 19 insertions(+), 16 deletions(-) rename openbsc/{src/osmo-bsc_mgcp => include/openbsc}/mgcp_transcode.h (100%) rename openbsc/src/{osmo-bsc_mgcp => libmgcp}/g711common.h (100%) rename openbsc/src/{osmo-bsc_mgcp => libmgcp}/mgcp_transcode.c (100%) diff --git a/openbsc/contrib/testconv/Makefile b/openbsc/contrib/testconv/Makefile index 90adecc..bb856f7 100644 --- a/openbsc/contrib/testconv/Makefile +++ b/openbsc/contrib/testconv/Makefile @@ -1,5 +1,5 @@ -OBJS = testconv_main.o mgcp_transcode.o +OBJS = testconv_main.o CC = gcc CFLAGS = -O0 -ggdb -Wall @@ -11,7 +11,6 @@ testconv: $(OBJS) $(CC) -o $@ $^ $(LDFLAGS) $(LIBS) testconv_main.o: testconv_main.c -mgcp_transcode.o: ../../src/osmo-bsc_mgcp/mgcp_transcode.c $(OBJS): $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< diff --git a/openbsc/contrib/testconv/testconv_main.c b/openbsc/contrib/testconv/testconv_main.c index e74c686..89dce1a 100644 --- a/openbsc/contrib/testconv/testconv_main.c +++ b/openbsc/contrib/testconv/testconv_main.c @@ -17,7 +17,7 @@ #error "Requires MGCP transcoding enabled (see --enable-mgcp-transcoding)" #endif -#include "src/osmo-bsc_mgcp/mgcp_transcode.h" +#include "openbsc/mgcp_transcode.h" static int audio_name_to_type(const char *name) { diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 8f7c1c4..6b08d07 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -13,7 +13,8 @@ noinst_HEADERS = abis_nm.h abis_rsl.h db.h gsm_04_08.h gsm_data.h \ osmo_bsc_rf.h osmo_bsc.h network_listen.h bsc_nat_sccp.h \ osmo_msc_data.h osmo_bsc_grace.h sms_queue.h abis_om2000.h \ bss.h gsm_data_shared.h control_cmd.h ipaccess.h mncc_int.h \ - arfcn_range_encode.h nat_rewrite_trie.h bsc_nat_callstats.h + arfcn_range_encode.h nat_rewrite_trie.h bsc_nat_callstats.h \ + mgcp_transcode.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.h b/openbsc/include/openbsc/mgcp_transcode.h similarity index 100% rename from openbsc/src/osmo-bsc_mgcp/mgcp_transcode.h rename to openbsc/include/openbsc/mgcp_transcode.h diff --git a/openbsc/src/libmgcp/Makefile.am b/openbsc/src/libmgcp/Makefile.am index 72f625d..bd02e61 100644 --- a/openbsc/src/libmgcp/Makefile.am +++ b/openbsc/src/libmgcp/Makefile.am @@ -1,7 +1,15 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) -AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS) -AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(COVERAGE_LDFLAGS) +AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS) \ + $(LIBBCG729_CFLAGS) +AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(COVERAGE_LDFLAGS) \ + $(LIBBCG729_LIBS) noinst_LIBRARIES = libmgcp.a +noinst_HEADERS = g711common.h + libmgcp_a_SOURCES = mgcp_protocol.c mgcp_network.c mgcp_vty.c + +if BUILD_MGCP_TRANSCODING + libmgcp_a_SOURCES += mgcp_transcode.c +endif diff --git a/openbsc/src/osmo-bsc_mgcp/g711common.h b/openbsc/src/libmgcp/g711common.h similarity index 100% rename from openbsc/src/osmo-bsc_mgcp/g711common.h rename to openbsc/src/libmgcp/g711common.h diff --git a/openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c b/openbsc/src/libmgcp/mgcp_transcode.c similarity index 100% rename from openbsc/src/osmo-bsc_mgcp/mgcp_transcode.c rename to openbsc/src/libmgcp/mgcp_transcode.c diff --git a/openbsc/src/osmo-bsc_mgcp/Makefile.am b/openbsc/src/osmo-bsc_mgcp/Makefile.am index a620e7a..da02380 100644 --- a/openbsc/src/osmo-bsc_mgcp/Makefile.am +++ b/openbsc/src/osmo-bsc_mgcp/Makefile.am @@ -1,16 +1,11 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) \ - $(LIBOSMOVTY_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) \ - $(LIBBCG729_CFLAGS) + $(LIBOSMOVTY_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) bin_PROGRAMS = osmo-bsc_mgcp osmo_bsc_mgcp_SOURCES = mgcp_main.c -if BUILD_MGCP_TRANSCODING - osmo_bsc_mgcp_SOURCES += mgcp_transcode.c -endif + osmo_bsc_mgcp_LDADD = $(top_builddir)/src/libcommon/libcommon.a \ $(top_builddir)/src/libmgcp/libmgcp.a -lrt \ $(LIBOSMOVTY_LIBS) $(LIBOSMOCORE_LIBS) $(LIBBCG729_LIBS) - -noinst_HEADERS = g711common.h mgcp_transcode.h diff --git a/openbsc/src/osmo-bsc_mgcp/mgcp_main.c b/openbsc/src/osmo-bsc_mgcp/mgcp_main.c index 6b72965..8c3808a 100644 --- a/openbsc/src/osmo-bsc_mgcp/mgcp_main.c +++ b/openbsc/src/osmo-bsc_mgcp/mgcp_main.c @@ -50,7 +50,7 @@ #include "../../bscconfig.h" #ifdef BUILD_MGCP_TRANSCODING -#include "mgcp_transcode.h" +#include "openbsc/mgcp_transcode.h" #endif /* this is here for the vty... it will never be called */ diff --git a/openbsc/tests/mgcp/Makefile.am b/openbsc/tests/mgcp/Makefile.am index 81f28ae..2bc2da6 100644 --- a/openbsc/tests/mgcp/Makefile.am +++ b/openbsc/tests/mgcp/Makefile.am @@ -18,7 +18,7 @@ mgcp_test_LDADD = $(top_builddir)/src/libbsc/libbsc.a \ $(LIBOSMOCORE_LIBS) -lrt -lm $(LIBOSMOSCCP_LIBS) $(LIBOSMOVTY_LIBS) \ $(LIBRARY_DL) -mgcp_transcoding_test_SOURCES = mgcp_transcoding_test.c $(top_builddir)/src/osmo-bsc_mgcp/mgcp_transcode.c +mgcp_transcoding_test_SOURCES = mgcp_transcoding_test.c mgcp_transcoding_test_LDADD = \ $(top_builddir)/src/libbsc/libbsc.a \ diff --git a/openbsc/tests/mgcp/mgcp_transcoding_test.c b/openbsc/tests/mgcp/mgcp_transcoding_test.c index e5da138..9ba2c4b 100644 --- a/openbsc/tests/mgcp/mgcp_transcoding_test.c +++ b/openbsc/tests/mgcp/mgcp_transcoding_test.c @@ -17,7 +17,7 @@ #error "Requires MGCP transcoding enabled (see --enable-mgcp-transcoding)" #endif -#include "src/osmo-bsc_mgcp/mgcp_transcode.h" +#include "openbsc/mgcp_transcode.h" uint8_t *audio_frame_l16[] = { }; -- 1.7.9.5 From jerlbeck at sysmocom.de Thu May 15 08:29:19 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Thu, 15 May 2014 10:29:19 +0200 Subject: [PATCH 11/11] mgcp: Set net_end audio params in recvonly mode In-Reply-To: <1400142559-26788-1-git-send-email-jerlbeck@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> <1400142559-26788-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <1400142559-26788-11-git-send-email-jerlbeck@sysmocom.de> Currently, if there is no SDP data in the MGCP message received from the net, the fields containing audio encoding information are not set in net_end. So in recvonly mode transcoding would not be set up correctly. This patch changes the implementation of the code handling CRCX and MDCX to use the codec signalled in the MGCP local connection options (field 'a:') if there isn't any SDP data. This is only halfway negotiation, because the codec is used blindly and not matched against the supported ones. Sponsored-by: On-Waves ehf --- openbsc/include/openbsc/mgcp_internal.h | 1 + openbsc/src/libmgcp/mgcp_protocol.c | 37 ++++++++++++++++++++++++++++--- openbsc/tests/mgcp/mgcp_test.c | 7 ++++++ openbsc/tests/mgcp/mgcp_test.ok | 5 +++++ 4 files changed, 47 insertions(+), 3 deletions(-) diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h index c7bc2a8..e877026 100644 --- a/openbsc/include/openbsc/mgcp_internal.h +++ b/openbsc/include/openbsc/mgcp_internal.h @@ -124,6 +124,7 @@ struct mgcp_rtp_tap { struct mgcp_lco { char *string; + char *codec; int pkt_period_min; /* time in ms */ int pkt_period_max; /* time in ms */ }; diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c index a903e3c..04f7750 100644 --- a/openbsc/src/libmgcp/mgcp_protocol.c +++ b/openbsc/src/libmgcp/mgcp_protocol.c @@ -582,7 +582,8 @@ static int set_audio_info(void *ctx, struct mgcp_rtp_end *rtp, talloc_free(rtp->audio_name); rtp->audio_name = NULL; - rtp->payload_type = payload_type; + if (payload_type >= 0) + rtp->payload_type = payload_type; if (!audio_name) { switch (payload_type) { @@ -597,7 +598,7 @@ static int set_audio_info(void *ctx, struct mgcp_rtp_end *rtp, } if (sscanf(audio_name, "%63[^/]/%d/%d", - audio_codec, &rate, &channels) < 2) + audio_codec, &rate, &channels) < 1) return -EINVAL; rtp->rate = rate; @@ -610,6 +611,20 @@ static int set_audio_info(void *ctx, struct mgcp_rtp_end *rtp, rtp->frame_duration_den = 1000; } + if (payload_type < 0) { + payload_type = 96; + if (rate == 8000 && channels == 1) { + if (!strcmp(audio_codec, "GSM")) + payload_type = 3; + else if (!strcmp(audio_codec, "PCMA")) + payload_type = 8; + else if (!strcmp(audio_codec, "G729")) + payload_type = 18; + } + + rtp->payload_type = payload_type; + } + if (channels != 1) LOGP(DMGCP, LOGL_NOTICE, "Channels != 1 in SDP: '%s'\n", audio_name); @@ -781,9 +796,12 @@ static int parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p) static void set_local_cx_options(void *ctx, struct mgcp_lco *lco, const char *options) { - char *p_opt; + char *p_opt, *a_opt; + char codec[9]; talloc_free(lco->string); + talloc_free(lco->codec); + lco->codec = NULL; lco->pkt_period_min = lco->pkt_period_max = 0; lco->string = talloc_strdup(ctx, options ? options : ""); @@ -791,6 +809,10 @@ static void set_local_cx_options(void *ctx, struct mgcp_lco *lco, if (p_opt && sscanf(p_opt, "p:%d-%d", &lco->pkt_period_min, &lco->pkt_period_max) == 1) lco->pkt_period_max = lco->pkt_period_min; + + a_opt = strstr(lco->string, "a:"); + if (a_opt && sscanf(a_opt, "a:%8[^,]", codec) == 1) + lco->codec = talloc_strdup(ctx, codec); } void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change, @@ -924,6 +946,9 @@ mgcp_header_done: tcfg->audio_fmtp_extra); if (have_sdp) parse_sdp_data(&endp->net_end, p); + else if (endp->local_options.codec) + set_audio_info(p->cfg, &endp->net_end, + -1, endp->local_options.codec); if (p->cfg->bts_force_ptime) { endp->bts_end.packet_duration_ms = p->cfg->bts_force_ptime; @@ -977,6 +1002,7 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p) struct mgcp_endpoint *endp = p->endp; int error_code = 500; int silent = 0; + int have_sdp = 0; char *line; const char *local_options = NULL; @@ -1016,6 +1042,7 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p) break; case '\0': /* SDP file begins */ + have_sdp = 1; parse_sdp_data(&endp->net_end, p); /* This will exhaust p->save, so the loop will * terminate next time. @@ -1031,6 +1058,10 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p) set_local_cx_options(endp->tcfg->endpoints, &endp->local_options, local_options); + if (!have_sdp && endp->local_options.codec) + set_audio_info(p->cfg, &endp->net_end, + -1, endp->local_options.codec); + setup_rtp_processing(endp); /* policy CB */ diff --git a/openbsc/tests/mgcp/mgcp_test.c b/openbsc/tests/mgcp/mgcp_test.c index 498a1d8..0552c72 100644 --- a/openbsc/tests/mgcp/mgcp_test.c +++ b/openbsc/tests/mgcp/mgcp_test.c @@ -168,6 +168,12 @@ static void test_strline(void) "a=rtpmap:99 AMR/8000\r\n" \ "a=ptime:40\r\n" +#define MDCX4_RO "MDCX 18983221 1 at mgw MGCP 1.0\r\n" \ + "M: recvonly\r" \ + "C: 2\r\n" \ + "I: 1\r\n" \ + "L: p:20, a:AMR, nt:IN\r\n" + #define SHORT2 "CRCX 1" #define SHORT2_RET "510 000000 FAIL\r\n" #define SHORT3 "CRCX 1 1 at mgw" @@ -257,6 +263,7 @@ static const struct mgcp_test tests[] = { { "MDCX4_PT2", MDCX4_PT2, MDCX4_RET("18983218"), 99, 126 }, { "MDCX4_PT3", MDCX4_PT3, MDCX4_RET("18983219"), 99, 126 }, { "MDCX4_SO", MDCX4_SO, MDCX4_RET("18983220"), 99, 126 }, + { "MDCX4_RO", MDCX4_RO, MDCX4_RET("18983221"), PTYPE_IGNORE, 126 }, { "DLCX", DLCX, DLCX_RET, -1, -1 }, { "CRCX_ZYN", CRCX_ZYN, CRCX_ZYN_RET, 97, 126 }, { "EMPTY", EMPTY, EMPTY_RET }, diff --git a/openbsc/tests/mgcp/mgcp_test.ok b/openbsc/tests/mgcp/mgcp_test.ok index 3901cfb..7301a81 100644 --- a/openbsc/tests/mgcp/mgcp_test.ok +++ b/openbsc/tests/mgcp/mgcp_test.ok @@ -49,6 +49,11 @@ Testing MDCX4_SO Detected packet duration: 40 Requested packetetization period: 20-20 Connection mode: 2: SEND +Testing MDCX4_RO +Dummy packets: 1 +Packet duration not set +Requested packetetization period: 20-20 +Connection mode: 1: RECV Testing DLCX Detected packet duration: 20 Requested packetization period not set -- 1.7.9.5 From holger at freyther.de Thu May 15 19:26:54 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Thu, 15 May 2014 21:26:54 +0200 Subject: [PATCH 01/11] mgcp: Add callbacks for payload processing In-Reply-To: <1400142559-26788-1-git-send-email-jerlbeck@sysmocom.de> References: <1399891147-31419-1-git-send-email-jerlbeck@sysmocom.de> <1400142559-26788-1-git-send-email-jerlbeck@sysmocom.de> Message-ID: <20140515192654.GK26903@xiaoyu.lan> On Thu, May 15, 2014 at 10:29:09AM +0200, Jacob Erlbeck wrote: Dear Jacob, > This patch adds the callbacks rtp_processing_cb and > setup_rtp_processing_cb to mgcp_config to support arbitrary RTP > payload processing. could you please make a smoke test with a bidirectional call (e.g. by calling our office number and picking up) and then rebase your code against master and merge with --no-ff thanks From anayuso at sysmocom.de Tue May 13 15:14:38 2014 From: anayuso at sysmocom.de (Alvaro Neira Ayuso) Date: Tue, 13 May 2014 17:14:38 +0200 Subject: [osmo-bts PATCH] src/osmo-bts-sysmo/l1_if.c: Forgot add utils header Message-ID: <1399994078-17246-1-git-send-email-anayuso@sysmocom.de> From: ?lvaro Neira Ayuso In the case that we use sysmobts_get_nominal_power inside the l1_if we receive a warning for forgive include that header. Signed-off-by: Alvaro Neira Ayuso --- src/osmo-bts-sysmo/l1_if.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index 79d506a..6834240 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -60,6 +60,7 @@ #include "hw_misc.h" #include "misc/sysmobts_par.h" #include "eeprom.h" +#include "utils.h" extern int pcu_direct; -- 1.7.10.4 From holger at freyther.de Wed May 14 05:12:35 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Wed, 14 May 2014 07:12:35 +0200 Subject: [osmo-bts PATCH] src/osmo-bts-sysmo/l1_if.c: Forgot add utils header In-Reply-To: <1399994078-17246-1-git-send-email-anayuso@sysmocom.de> References: <1399994078-17246-1-git-send-email-anayuso@sysmocom.de> Message-ID: <20140514051235.GE26057@xiaoyu.lan> On Tue, May 13, 2014 at 05:14:38PM +0200, Alvaro Neira Ayuso wrote: Good Morning, > In the case that we use sysmobts_get_nominal_power inside the l1_if we receive > a warning for forgive include that header. Please try again. "forgive" is certainly not the right word here. Be more explicit with the "in the case". It applies to sysmobts-v2 and all versions above 2.2.0. Include the warning generated by the compiler in the commit message as well. E.g. look at 666fec7ff23e125730d7e13aa6d68112cde082de for an example. cheers holger From anayuso at sysmocom.de Wed May 14 16:22:45 2014 From: anayuso at sysmocom.de (Alvaro Neira Ayuso) Date: Wed, 14 May 2014 18:22:45 +0200 Subject: [osmo-bts PATCH] src/osmo-bts-sysmo/l1_if.c: Forgot add utils header In-Reply-To: <1399994078-17246-1-git-send-email-anayuso@sysmocom.de> References: <1399994078-17246-1-git-send-email-anayuso@sysmocom.de> Message-ID: <1400084565-14616-1-git-send-email-anayuso@sysmocom.de> From: ?lvaro Neira Ayuso In sysmocom-v2 and all versions above 2.2.0, when we use sysmobts_get_nominal_power for calculating the power transmitter inside the l1_if, we receive a warning for forgot include that header. l1_if.c: In function 'l1if_activate_rf': l1_if.c:1144:6: warning: implicit declaration of function 'sysmobts_get_nominal_power' [-Wimplicit-function-declaration] Signed-off-by: Alvaro Neira Ayuso --- src/osmo-bts-sysmo/l1_if.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index 79d506a..6834240 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -60,6 +60,7 @@ #include "hw_misc.h" #include "misc/sysmobts_par.h" #include "eeprom.h" +#include "utils.h" extern int pcu_direct; -- 1.7.10.4 From holger at freyther.de Thu May 15 09:24:06 2014 From: holger at freyther.de (Holger Freyther) Date: Thu, 15 May 2014 11:24:06 +0200 Subject: [PATCH] misc: Address style issues pointed out by the cppcheck application Message-ID: <1400145846-18972-1-git-send-email-holger@freyther.de> From: Holger Hans Peter Freyther Use the variable only in the scope it is actually used. This could reduce the used stack space but that does not really matter to us right now. [src/gprs/gb_proxy.c:739]: (style) The scope of the variable 'peer' can be reduced. [src/libbsc/abis_nm.c:281]: (style) The scope of the variable 'p_text' can be reduced. [src/libbsc/abis_nm.c:547]: (style) The scope of the variable 'msg' can be reduced. [src/libbsc/abis_nm.c:1069]: (style) The scope of the variable 'rc' can be reduced. [src/libbsc/abis_nm.c:2741]: (style) The scope of the variable 'msg' can be reduced. [src/libbsc/abis_rsl.c:1092]: (style) The scope of the variable 'rc' can be reduced. [src/libbsc/arfcn_range_encode.c:57]: (style) The scope of the variable 'n' can be reduced. [src/libbsc/bsc_api.c:642]: (style) The scope of the variable 'rc' can be reduced. [src/ipaccess/ipaccess-find.c:176]: (style) The scope of the variable 'rc' can be reduced. [src/libbsc/bsc_vty.c:1040]: (style) The scope of the variable 'lchan' can be reduced. [src/libbsc/bsc_vty.c:1041]: (style) The scope of the variable 'trx_nr' can be reduced. [src/libbsc/bsc_vty.c:1041]: (style) The scope of the variable 'ts_nr' can be reduced. [src/libbsc/bsc_vty.c:1041]: (style) The scope of the variable 'lchan_nr' can be reduced. [src/libbsc/bts_nokia_site.c:1167]: (style) The scope of the variable 'noh' can be reduced. [src/libbsc/bts_nokia_site.c:1426]: (style) The scope of the variable 'msg' can be reduced. [src/libbsc/bts_nokia_site.c:1310]: (style) The scope of the variable 'constructed' can be reduced. [src/libbsc/bts_nokia_site.c:1368]: (style) The scope of the variable 'constructed' can be reduced. [src/libbsc/chan_alloc.c:435]: (style) The scope of the variable 'lchan' can be reduced. [src/libbsc/system_information.c:337]: (style) The scope of the variable 'cur_bts' can be reduced. [src/libcommon/gsm_data.c:234]: (style) The scope of the variable 'bts' can be reduced. [src/libtrau/rtp_proxy.c:114]: (style) The scope of the variable 'rtpxh' can be reduced. [src/libtrau/rtp_proxy.c:118]: (style) The scope of the variable 'x_len' can be reduced. [src/libmsc/transaction.c:128]: (style) The scope of the variable 'j' can be reduced. [src/libtrau/trau_mux.c:158]: (style) The scope of the variable 'me2' can be reduced. [src/osmo-bsc/osmo_bsc_filter.c:320]: (style) The scope of the variable 'lai' can be reduced. [src/osmo-bsc/osmo_bsc_msc.c:410]: (style) The scope of the variable 'msg' can be reduced. [src/osmo-bsc/osmo_bsc_sccp.c:44]: (style) The scope of the variable 'msg' can be reduced. [src/osmo-bsc/osmo_bsc_sccp.c:57]: (style) The scope of the variable 'msg' can be reduced. [src/osmo-bsc_mgcp/mgcp_main.c:146]: (style) The scope of the variable 'i' can be reduced. [src/osmo-bsc_nat/bsc_nat.c:444]: (style) The scope of the variable 'udt' can be reduced. [src/osmo-bsc_nat/bsc_nat_vty.c:544]: (style) The scope of the variable 'rewr' can be reduced. [src/osmo-bsc_nat/bsc_ussd.c:375]: (style) The scope of the variable 'lst' can be reduced. [src/libmsc/gsm_04_08.c:683]: (style) The scope of the variable 'local_time' can be reduced. [src/libmsc/gsm_04_08.c:1638]: (style) The scope of the variable 'rc' can be reduced. [src/libmsc/gsm_04_08.c:2938]: (style) The scope of the variable 'transt' can be reduced. [src/libtrau/trau_mux.c:332]: (style) The scope of the variable 'ue' can be reduced. --- openbsc/src/gprs/gb_proxy.c | 2 +- openbsc/src/ipaccess/ipaccess-find.c | 2 +- openbsc/src/libbsc/abis_nm.c | 11 +++++------ openbsc/src/libbsc/abis_rsl.c | 2 +- openbsc/src/libbsc/arfcn_range_encode.c | 4 ++-- openbsc/src/libbsc/bsc_api.c | 2 +- openbsc/src/libbsc/bsc_vty.c | 9 +++++---- openbsc/src/libbsc/bts_nokia_site.c | 8 ++++---- openbsc/src/libbsc/chan_alloc.c | 2 +- openbsc/src/libbsc/system_information.c | 3 ++- openbsc/src/libcommon/gsm_data.c | 2 +- openbsc/src/libmsc/gsm_04_08.c | 10 ++++++---- openbsc/src/libmsc/transaction.c | 4 ++-- openbsc/src/libtrau/rtp_proxy.c | 5 +++-- openbsc/src/libtrau/trau_mux.c | 9 ++++++--- openbsc/src/osmo-bsc/osmo_bsc_filter.c | 2 +- openbsc/src/osmo-bsc/osmo_bsc_msc.c | 3 +-- openbsc/src/osmo-bsc/osmo_bsc_sccp.c | 8 ++++---- openbsc/src/osmo-bsc_mgcp/mgcp_main.c | 2 +- openbsc/src/osmo-bsc_nat/bsc_nat.c | 3 ++- openbsc/src/osmo-bsc_nat/bsc_nat_vty.c | 3 +-- openbsc/src/osmo-bsc_nat/bsc_ussd.c | 2 +- 22 files changed, 52 insertions(+), 46 deletions(-) diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index 3c41529..3639650 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -736,7 +736,6 @@ int gbprox_signal(unsigned int subsys, unsigned int signal, { struct ns_signal_data *nssd = signal_data; struct gprs_nsvc *nsvc = nssd->nsvc; - struct gbprox_peer *peer; if (subsys != SS_L_NS) return 0; @@ -759,6 +758,7 @@ int gbprox_signal(unsigned int subsys, unsigned int signal, } if (!nsvc->remote_end_is_sgsn) { + struct gbprox_peer *peer; /* from BSS to SGSN */ peer = peer_by_nsei(nsvc->nsei); if (!peer) { diff --git a/openbsc/src/ipaccess/ipaccess-find.c b/openbsc/src/ipaccess/ipaccess-find.c index c8de157..19acf26 100644 --- a/openbsc/src/ipaccess/ipaccess-find.c +++ b/openbsc/src/ipaccess/ipaccess-find.c @@ -173,7 +173,6 @@ int main(int argc, char **argv) { struct osmo_fd bfd; char *ifname = NULL; - int rc; printf("ipaccess-find (C) 2009 by Harald Welte\n"); printf("This is FREE SOFTWARE with ABSOLUTELY NO WARRANTY\n\n"); @@ -203,6 +202,7 @@ int main(int argc, char **argv) printf("Trying to find ip.access BTS by broadcast UDP...\n"); while (1) { + int rc; rc = osmo_select_main(0); if (rc < 0) exit(3); diff --git a/openbsc/src/libbsc/abis_nm.c b/openbsc/src/libbsc/abis_nm.c index 3bf55ec..00fd479 100644 --- a/openbsc/src/libbsc/abis_nm.c +++ b/openbsc/src/libbsc/abis_nm.c @@ -278,7 +278,6 @@ static int rx_fail_evt_rep(struct msgb *mb) struct e1inp_sign_link *sign_link = mb->dst; struct tlv_parsed tp; const uint8_t *p_val; - char *p_text; LOGPC(DNM, LOGL_ERROR, "Failure Event Report "); @@ -295,6 +294,7 @@ static int rx_fail_evt_rep(struct msgb *mb) LOGPC(DNM, LOGL_ERROR, "Probable cause= %02X %02X %02X ", p_val[0], p_val[1], p_val[2]); } if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) { + char *p_text; p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT); p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT)); if (p_text) { @@ -544,9 +544,10 @@ static int abis_nm_rx_lmt_event(struct msgb *mb) void abis_nm_queue_send_next(struct gsm_bts *bts) { int wait = 0; - struct msgb *msg; + /* the queue is empty */ while (!llist_empty(&bts->abis_queue)) { + struct msgb *msg; msg = msgb_dequeue(&bts->abis_queue); wait = OBSC_NM_W_ACK_CB(msg); _abis_nm_sendmsg(msg); @@ -1066,9 +1067,8 @@ static void sw_close_file(struct abis_nm_sw *sw) /* Fill the window */ static int sw_fill_window(struct abis_nm_sw *sw) { - int rc; - while (sw->seg_in_window < sw->window_size) { + int rc; rc = sw_load_segment(sw); if (rc < 0) return rc; @@ -2738,9 +2738,8 @@ int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf) void abis_nm_clear_queue(struct gsm_bts *bts) { - struct msgb *msg; - while (!llist_empty(&bts->abis_queue)) { + struct msgb *msg; msg = msgb_dequeue(&bts->abis_queue); msgb_free(msg); } diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index 425dd8d..398f243 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -1089,7 +1089,6 @@ static int rsl_rx_meas_res(struct msgb *msg) struct gsm_meas_rep *mr = lchan_next_meas_rep(msg->lchan); uint8_t len; const uint8_t *val; - int rc; /* check if this channel is actually active */ /* FIXME: maybe this check should be way more generic/centralized */ @@ -1145,6 +1144,7 @@ static int rsl_rx_meas_res(struct msgb *msg) mr->ms_l1.ta >>= 2; } if (TLVP_PRESENT(&tp, RSL_IE_L3_INFO)) { + int rc; msg->l3h = (uint8_t *) TLVP_VAL(&tp, RSL_IE_L3_INFO); rc = gsm48_parse_meas_rep(mr, msg); if (rc < 0) diff --git a/openbsc/src/libbsc/arfcn_range_encode.c b/openbsc/src/libbsc/arfcn_range_encode.c index e67bf0a..d2230a6 100644 --- a/openbsc/src/libbsc/arfcn_range_encode.c +++ b/openbsc/src/libbsc/arfcn_range_encode.c @@ -54,12 +54,12 @@ static inline int mod(int data, int range) */ int range_enc_find_index(const int range, const int *freqs, const int size) { - int i, j, n; + int i, j; const int RANGE_DELTA = (range - 1) / 2; for (i = 0; i < size; ++i) { - n = 0; + int n = 0; for (j = 0; j < size; ++j) { if (mod(freqs[j] - freqs[i], range) <= RANGE_DELTA) n += 1; diff --git a/openbsc/src/libbsc/bsc_api.c b/openbsc/src/libbsc/bsc_api.c index e567038..0a8a2a8 100644 --- a/openbsc/src/libbsc/bsc_api.c +++ b/openbsc/src/libbsc/bsc_api.c @@ -639,7 +639,6 @@ static void dispatch_dtap(struct gsm_subscriber_connection *conn, /*! \brief RSL has received a DATA INDICATION with L3 from MS */ int gsm0408_rcvmsg(struct msgb *msg, uint8_t link_id) { - int rc; struct bsc_api *api = msg->lchan->ts->trx->bts->network->bsc_api; struct gsm_lchan *lchan; @@ -657,6 +656,7 @@ int gsm0408_rcvmsg(struct msgb *msg, uint8_t link_id) dispatch_dtap(lchan->conn, link_id, msg); } else { /* allocate a new connection */ + int rc; rc = BSC_API_CONN_POL_REJECT; lchan->conn = subscr_con_allocate(msg->lchan); if (!lchan->conn) { diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c index 9129059..d1ef244 100644 --- a/openbsc/src/libbsc/bsc_vty.c +++ b/openbsc/src/libbsc/bsc_vty.c @@ -1037,8 +1037,7 @@ static int lchan_summary(struct vty *vty, int argc, const char **argv, struct gsm_bts *bts; struct gsm_bts_trx *trx; struct gsm_bts_trx_ts *ts; - struct gsm_lchan *lchan; - int bts_nr, trx_nr, ts_nr, lchan_nr; + int bts_nr; if (argc >= 1) { /* use the BTS number that the user has specified */ @@ -1054,7 +1053,7 @@ static int lchan_summary(struct vty *vty, int argc, const char **argv, return dump_lchan_bts(bts, vty, dump_cb); } if (argc >= 2) { - trx_nr = atoi(argv[1]); + int trx_nr = atoi(argv[1]); if (trx_nr >= bts->num_trx) { vty_out(vty, "%% can't find TRX %s%s", argv[1], VTY_NEWLINE); @@ -1066,7 +1065,7 @@ static int lchan_summary(struct vty *vty, int argc, const char **argv, return dump_lchan_trx(trx, vty, dump_cb); } if (argc >= 3) { - ts_nr = atoi(argv[2]); + int ts_nr = atoi(argv[2]); if (ts_nr >= TRX_NR_TS) { vty_out(vty, "%% can't find TS %s%s", argv[2], VTY_NEWLINE); @@ -1078,6 +1077,8 @@ static int lchan_summary(struct vty *vty, int argc, const char **argv, return dump_lchan_trx_ts(ts, vty, dump_cb); } if (argc >= 4) { + struct gsm_lchan *lchan; + int lchan_nr; lchan_nr = atoi(argv[3]); if (lchan_nr >= TS_MAX_LCHAN) { vty_out(vty, "%% can't find LCHAN %s%s", argv[3], diff --git a/openbsc/src/libbsc/bts_nokia_site.c b/openbsc/src/libbsc/bts_nokia_site.c index 376a048..ae13335 100644 --- a/openbsc/src/libbsc/bts_nokia_site.c +++ b/openbsc/src/libbsc/bts_nokia_site.c @@ -1164,7 +1164,6 @@ static int abis_nm_send_multi_segments(struct gsm_bts *bts, uint8_t msg_type, while (len_remain) { struct abis_om_hdr *oh; - struct abis_om_nokia_hdr *noh; struct msgb *msg = nm_msgb_alloc(); if (seq == 0) @@ -1176,6 +1175,7 @@ static int abis_nm_send_multi_segments(struct gsm_bts *bts, uint8_t msg_type, len_to_send = max_send; if (seq == 0) { + struct abis_om_nokia_hdr *noh; /* first segment */ oh = (struct abis_om_hdr *)msgb_put(msg, ABIS_OM_NOKIA_HDR_SIZE @@ -1307,10 +1307,10 @@ static int find_element(uint8_t * data, int len, uint16_t id, uint8_t * value, uint8_t ub; int idx = 0; int found = 0; - int constructed __attribute__((unused)); uint16_t id_value; for (;;) { + int constructed __attribute__((unused)); GET_NEXT_BYTE; @@ -1365,11 +1365,11 @@ static int dump_elements(uint8_t * data, int len) { uint8_t ub; int idx = 0; - int constructed; uint16_t id_value; static char indent[100] = ""; /* TODO: move static to BTS context */ for (;;) { + int constructed; GET_NEXT_BYTE; @@ -1423,9 +1423,9 @@ static int dump_elements(uint8_t * data, int len) static void nokia_abis_nm_queue_send_next(struct gsm_bts *bts) { int wait = 0; - struct msgb *msg; /* the queue is empty */ while (!llist_empty(&bts->abis_queue)) { + struct msgb *msg; msg = msgb_dequeue(&bts->abis_queue); wait = OBSC_NM_W_ACK_CB(msg); abis_sendmsg(msg); diff --git a/openbsc/src/libbsc/chan_alloc.c b/openbsc/src/libbsc/chan_alloc.c index 9b74329..255c79d 100644 --- a/openbsc/src/libbsc/chan_alloc.c +++ b/openbsc/src/libbsc/chan_alloc.c @@ -432,9 +432,9 @@ struct gsm_subscriber_connection *connection_for_subscr(struct gsm_subscriber *s { struct gsm_bts *bts; struct gsm_network *net = subscr->net; - struct gsm_lchan *lchan; llist_for_each_entry(bts, &net->bts_list, list) { + struct gsm_lchan *lchan; lchan = lchan_find(bts, subscr); if (lchan) return lchan->conn; diff --git a/openbsc/src/libbsc/system_information.c b/openbsc/src/libbsc/system_information.c index a3deefc..7b7b3d7 100644 --- a/openbsc/src/libbsc/system_information.c +++ b/openbsc/src/libbsc/system_information.c @@ -334,7 +334,6 @@ static int bitvec2freq_list(uint8_t *chan_list, struct bitvec *bv, static int generate_bcch_chan_list(uint8_t *chan_list, struct gsm_bts *bts, int si5, int bis, int ter) { - struct gsm_bts *cur_bts; struct bitvec *bv; if (si5 && bts->neigh_list_manual_mode == NL_MODE_MANUAL_SI5SEP) @@ -344,6 +343,8 @@ static int generate_bcch_chan_list(uint8_t *chan_list, struct gsm_bts *bts, /* Generate list of neighbor cells if we are in automatic mode */ if (bts->neigh_list_manual_mode == NL_MODE_AUTOMATIC) { + struct gsm_bts *cur_bts; + /* Zero-initialize the bit-vector */ memset(bv->data, 0, bv->data_len); diff --git a/openbsc/src/libcommon/gsm_data.c b/openbsc/src/libcommon/gsm_data.c index 5f7e32e..5b42269 100644 --- a/openbsc/src/libcommon/gsm_data.c +++ b/openbsc/src/libcommon/gsm_data.c @@ -231,13 +231,13 @@ struct gsm_bts *gsm_bts_by_lac(struct gsm_network *net, unsigned int lac, struct gsm_bts *start_bts) { int i; - struct gsm_bts *bts; int skip = 0; if (start_bts) skip = 1; for (i = 0; i < net->num_bts; i++) { + struct gsm_bts *bts; bts = gsm_bts_num(net, i); if (skip) { diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index df93433..0f77a86 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -680,7 +680,6 @@ int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn) time_t cur_t; struct tm* gmt_time; - struct tm* local_time; int tzunits; int dst = 0; @@ -781,6 +780,8 @@ int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn) dst = bts->tz.dst; } else { + struct tm* local_time; + /* Need to get GSM offset and convert into 15 min units */ /* This probably breaks if gmtoff returns a value not evenly divisible by 15? */ local_time = localtime(&cur_t); @@ -1635,7 +1636,6 @@ static int tch_recv_mncc(struct gsm_network *net, uint32_t callref, int enable) struct gsm_trans *trans; struct gsm_lchan *lchan; struct gsm_bts *bts; - int rc; /* Find callref */ trans = trans_find_by_callref(net, callref); @@ -1669,7 +1669,7 @@ static int tch_recv_mncc(struct gsm_network *net, uint32_t callref, int enable) } if (enable) { /* connect the TCH's to our RTP proxy */ - rc = rsl_ipacc_mdcx_to_rtpsock(lchan); + int rc = rsl_ipacc_mdcx_to_rtpsock(lchan); if (rc < 0) return rc; /* assign socket to application interface */ @@ -2935,7 +2935,7 @@ static struct downstate { int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg) { int i, rc = 0; - struct gsm_trans *trans = NULL, *transt; + struct gsm_trans *trans = NULL; struct gsm_subscriber_connection *conn = NULL; struct gsm_bts *bts = NULL; struct gsm_mncc *data = arg, rel; @@ -3069,6 +3069,8 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg) /* If subscriber has no lchan */ if (!conn) { + struct gsm_trans *transt; + /* find transaction with this subscriber already paging */ llist_for_each_entry(transt, &net->trans_list, entry) { /* Transaction of our lchan? */ diff --git a/openbsc/src/libmsc/transaction.c b/openbsc/src/libmsc/transaction.c index e425e67..cde303f 100644 --- a/openbsc/src/libmsc/transaction.c +++ b/openbsc/src/libmsc/transaction.c @@ -125,7 +125,7 @@ int trans_assign_trans_id(struct gsm_subscriber *subscr, struct gsm_network *net = subscr->net; struct gsm_trans *trans; unsigned int used_tid_bitmask = 0; - int i, j, h; + int i, h; if (ti_flag) ti_flag = 0x8; @@ -144,7 +144,7 @@ int trans_assign_trans_id(struct gsm_subscriber *subscr, if (used_tid_bitmask & (1 << (h | ti_flag))) break; for (i = 0; i < 7; i++) { - j = ((h + i) % 7) | ti_flag; + int j = ((h + i) % 7) | ti_flag; if ((used_tid_bitmask & (1 << j)) == 0) return j; } diff --git a/openbsc/src/libtrau/rtp_proxy.c b/openbsc/src/libtrau/rtp_proxy.c index 143bfa0..0b42b8d 100644 --- a/openbsc/src/libtrau/rtp_proxy.c +++ b/openbsc/src/libtrau/rtp_proxy.c @@ -111,11 +111,9 @@ static int rtp_decode(struct msgb *msg, uint32_t callref, struct msgb **data) struct msgb *new_msg; struct gsm_data_frame *frame; struct rtp_hdr *rtph = (struct rtp_hdr *)msg->data; - struct rtp_x_hdr *rtpxh; uint8_t *payload; int payload_len; int msg_type; - int x_len; if (msg->len < 12) { DEBUGPC(DLMUX, "received RTP frame too short (len = %d)\n", @@ -135,6 +133,9 @@ static int rtp_decode(struct msgb *msg, uint32_t callref, struct msgb **data) return -EINVAL; } if (rtph->extension) { + struct rtp_x_hdr *rtpxh; + int x_len; + if (payload_len < sizeof(struct rtp_x_hdr)) { DEBUGPC(DLMUX, "received RTP frame too short for " "extension header\n"); diff --git a/openbsc/src/libtrau/trau_mux.c b/openbsc/src/libtrau/trau_mux.c index fd1895f..8ad045b 100644 --- a/openbsc/src/libtrau/trau_mux.c +++ b/openbsc/src/libtrau/trau_mux.c @@ -155,10 +155,10 @@ int trau_mux_map_lchan(const struct gsm_lchan *src, /* unmap one particular subslot from another subslot */ int trau_mux_unmap(const struct gsm_e1_subslot *ss, uint32_t callref) { - struct map_entry *me, *me2; struct upqueue_entry *ue, *ue2; - if (ss) + if (ss) { + struct map_entry *me, *me2; llist_for_each_entry_safe(me, me2, &ss_map, list) { if (!memcmp(&me->src, ss, sizeof(*ss)) || !memcmp(&me->dst, ss, sizeof(*ss))) { @@ -166,6 +166,8 @@ int trau_mux_unmap(const struct gsm_e1_subslot *ss, uint32_t callref) return 0; } } + } + llist_for_each_entry_safe(ue, ue2, &ss_upqueue, list) { if (ue->callref == callref) { llist_del(&ue->list); @@ -327,7 +329,6 @@ int trau_mux_input(struct gsm_e1_subslot *src_e1_ss, uint8_t trau_bits_out[TRAU_FRAME_BITS]; struct gsm_e1_subslot *dst_e1_ss = lookup_trau_mux_map(src_e1_ss); struct subch_mux *mx; - struct upqueue_entry *ue; int rc; /* decode TRAU, change it to downlink, re-encode */ @@ -337,6 +338,8 @@ int trau_mux_input(struct gsm_e1_subslot *src_e1_ss, if (!dst_e1_ss) { struct msgb *msg = NULL; + struct upqueue_entry *ue; + /* frame shall be sent to upqueue */ if (!(ue = lookup_trau_upqueue(src_e1_ss))) return -EINVAL; diff --git a/openbsc/src/osmo-bsc/osmo_bsc_filter.c b/openbsc/src/osmo-bsc/osmo_bsc_filter.c index 608f525..229a59d 100644 --- a/openbsc/src/osmo-bsc/osmo_bsc_filter.c +++ b/openbsc/src/osmo-bsc/osmo_bsc_filter.c @@ -317,7 +317,6 @@ int bsc_scan_msc_msg(struct gsm_subscriber_connection *conn, struct msgb *msg) { struct osmo_msc_data *msc; struct gsm_network *net; - struct gsm48_loc_area_id *lai; struct gsm48_hdr *gh; uint8_t mtype; int length = msgb_l3len(msg); @@ -336,6 +335,7 @@ int bsc_scan_msc_msg(struct gsm_subscriber_connection *conn, struct msgb *msg) if (mtype == GSM48_MT_MM_LOC_UPD_ACCEPT) { if (msc->core_ncc != -1 || msc->core_mcc != -1) { + struct gsm48_loc_area_id *lai; if (msgb_l3len(msg) >= sizeof(*gh) + sizeof(*lai)) { lai = (struct gsm48_loc_area_id *) &gh->data[0]; gsm48_generate_lai(lai, net->country_code, diff --git a/openbsc/src/osmo-bsc/osmo_bsc_msc.c b/openbsc/src/osmo-bsc/osmo_bsc_msc.c index 0acc290..064977f 100644 --- a/openbsc/src/osmo-bsc/osmo_bsc_msc.c +++ b/openbsc/src/osmo-bsc/osmo_bsc_msc.c @@ -407,9 +407,8 @@ static void send_lacs(struct gsm_network *net, struct bsc_msc_connection *conn) static void initialize_if_needed(struct bsc_msc_connection *conn) { - struct msgb *msg; - if (!conn->is_authenticated) { + struct msgb *msg; /* send a gsm 08.08 reset message from here */ msg = gsm0808_create_reset(); if (!msg) { diff --git a/openbsc/src/osmo-bsc/osmo_bsc_sccp.c b/openbsc/src/osmo-bsc/osmo_bsc_sccp.c index 3dd0a52..bc7a314 100644 --- a/openbsc/src/osmo-bsc/osmo_bsc_sccp.c +++ b/openbsc/src/osmo-bsc/osmo_bsc_sccp.c @@ -41,9 +41,9 @@ static LLIST_HEAD(active_connections); static void free_queued(struct osmo_bsc_sccp_con *conn) { - struct msgb *msg; - while (!llist_empty(&conn->sccp_queue)) { + struct msgb *msg; + /* this is not allowed to fail */ msg = msgb_dequeue(&conn->sccp_queue); msgb_free(msg); @@ -54,9 +54,9 @@ static void free_queued(struct osmo_bsc_sccp_con *conn) static void send_queued(struct osmo_bsc_sccp_con *conn) { - struct msgb *msg; - while (!llist_empty(&conn->sccp_queue)) { + struct msgb *msg; + /* this is not allowed to fail */ msg = msgb_dequeue(&conn->sccp_queue); sccp_connection_write(conn->sccp, msg); diff --git a/openbsc/src/osmo-bsc_mgcp/mgcp_main.c b/openbsc/src/osmo-bsc_mgcp/mgcp_main.c index 14ec221..deda5cc 100644 --- a/openbsc/src/osmo-bsc_mgcp/mgcp_main.c +++ b/openbsc/src/osmo-bsc_mgcp/mgcp_main.c @@ -143,7 +143,6 @@ static int read_call_agent(struct osmo_fd *fd, unsigned int what) socklen_t slen = sizeof(addr); struct msgb *msg; struct msgb *resp; - int i; msg = (struct msgb *) fd->data; @@ -170,6 +169,7 @@ static int read_call_agent(struct osmo_fd *fd, unsigned int what) } if (reset_endpoints) { + int i; LOGP(DMGCP, LOGL_NOTICE, "Asked to reset endpoints: %d/%d\n", reset_trunk->trunk_nr, reset_trunk->trunk_type); diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat.c b/openbsc/src/osmo-bsc_nat/bsc_nat.c index 1aef27e..dd9d25a 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat.c @@ -441,10 +441,11 @@ static void bsc_send_con_release(struct bsc_connection *bsc, /* 2. release the BSC side */ if (con->con_type == NAT_CON_TYPE_LU) { - struct msgb *payload, *udt; + struct msgb *payload; payload = gsm48_create_loc_upd_rej(cause->lu_reject_cause); if (payload) { + struct msgb *udt; gsm0808_prepend_dtap_header(payload, 0); udt = sccp_create_dt1(&con->real_ref, payload->data, payload->len); if (udt) diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c b/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c index 261a194..672ba40 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c @@ -541,10 +541,9 @@ DEFUN(cfg_nat_no_imsi_black_list_fn, static int replace_rules(struct bsc_nat *nat, char **name, struct llist_head *head, const char *file) { - struct osmo_config_list *rewr = NULL; - bsc_replace_string(nat, name, file); if (*name) { + struct osmo_config_list *rewr; rewr = osmo_config_list_parse(nat, *name); bsc_nat_num_rewr_entry_adapt(nat, head, rewr); talloc_free(rewr); diff --git a/openbsc/src/osmo-bsc_nat/bsc_ussd.c b/openbsc/src/osmo-bsc_nat/bsc_ussd.c index 5f073bf..66d863e 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_ussd.c +++ b/openbsc/src/osmo-bsc_nat/bsc_ussd.c @@ -372,7 +372,6 @@ int bsc_ussd_check(struct nat_sccp_connection *con, struct bsc_nat_parsed *parse uint8_t proto; uint8_t ti; struct gsm48_hdr *hdr48; - struct bsc_nat_acc_lst *lst; struct ussd_request req; /* @@ -412,6 +411,7 @@ int bsc_ussd_check(struct nat_sccp_connection *con, struct bsc_nat_parsed *parse return 0; if (msg_type == GSM0480_MTYPE_REGISTER) { + struct bsc_nat_acc_lst *lst; /* now check if it is a IMSI we care about */ lst = bsc_nat_acc_lst_find(con->bsc->nat, -- 1.9.1 From holger at freyther.de Thu May 15 09:24:28 2014 From: holger at freyther.de (Holger Freyther) Date: Thu, 15 May 2014 11:24:28 +0200 Subject: [PATCH] ctrl: Introduce a macro for read-only attributes and use it Message-ID: <1400145868-19050-1-git-send-email-holger@freyther.de> From: Holger Hans Peter Freyther Certain attributes are read-only. Add a macro to make it more easy to define those. --- openbsc/include/openbsc/control_cmd.h | 20 ++++++++++++++++++ openbsc/src/osmo-bsc/osmo_bsc_ctrl.c | 38 +++-------------------------------- 2 files changed, 23 insertions(+), 35 deletions(-) diff --git a/openbsc/include/openbsc/control_cmd.h b/openbsc/include/openbsc/control_cmd.h index 8aede15..df5ae23 100644 --- a/openbsc/include/openbsc/control_cmd.h +++ b/openbsc/include/openbsc/control_cmd.h @@ -172,6 +172,26 @@ static struct ctrl_cmd_element cmd_##cmdname = { \ .verify = &verify_##cmdname, \ } +#define CTRL_CMD_DEFINE_RO(cmdname, cmdstr) \ +static int get_##cmdname(struct ctrl_cmd *cmd, void *data); \ +static inline int set_##cmdname(struct ctrl_cmd *cmd, void *data) \ +{ \ + cmd->reply = "Read Only attribute"; \ + return CTRL_CMD_ERROR; \ +} \ +static inline int verify_##cmdname(struct ctrl_cmd *cmd, const char *value, void *data) \ +{ \ + cmd->reply = "Read Only attribute"; \ + return 1; \ +} \ +static struct ctrl_cmd_element cmd_##cmdname = { \ + .name = cmdstr, \ + .param = NULL, \ + .get = &get_##cmdname, \ + .set = &set_##cmdname, \ + .verify = &verify_##cmdname, \ +} + struct gsm_network; #endif /* _CONTROL_CMD_H */ diff --git a/openbsc/src/osmo-bsc/osmo_bsc_ctrl.c b/openbsc/src/osmo-bsc/osmo_bsc_ctrl.c index e32218d..d3593de 100644 --- a/openbsc/src/osmo-bsc/osmo_bsc_ctrl.c +++ b/openbsc/src/osmo-bsc/osmo_bsc_ctrl.c @@ -58,7 +58,7 @@ void osmo_bsc_send_trap(struct ctrl_cmd *cmd, struct bsc_msc_connection *msc_con talloc_free(trap); } -CTRL_CMD_DEFINE(msc_connection_status, "msc_connection_status"); +CTRL_CMD_DEFINE_RO(msc_connection_status, "msc_connection_status"); static int msc_connection_status = 0; static int get_msc_connection_status(struct ctrl_cmd *cmd, void *data) @@ -70,17 +70,6 @@ static int get_msc_connection_status(struct ctrl_cmd *cmd, void *data) return CTRL_CMD_REPLY; } -static int set_msc_connection_status(struct ctrl_cmd *cmd, void *data) -{ - return CTRL_CMD_ERROR; -} - -static int verify_msc_connection_status(struct ctrl_cmd *cmd, const char *value, void *data) -{ - cmd->reply = "Read-only property"; - return 1; -} - static int msc_connection_status_trap_cb(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data) { struct ctrl_cmd *cmd; @@ -114,7 +103,7 @@ static int msc_connection_status_trap_cb(unsigned int subsys, unsigned int signa return 0; } -CTRL_CMD_DEFINE(bts_connection_status, "bts_connection_status"); +CTRL_CMD_DEFINE_RO(bts_connection_status, "bts_connection_status"); static int bts_connection_status = 0; static int get_bts_connection_status(struct ctrl_cmd *cmd, void *data) @@ -126,17 +115,6 @@ static int get_bts_connection_status(struct ctrl_cmd *cmd, void *data) return CTRL_CMD_REPLY; } -static int set_bts_connection_status(struct ctrl_cmd *cmd, void *data) -{ - return CTRL_CMD_ERROR; -} - -static int verify_bts_connection_status(struct ctrl_cmd *cmd, const char *value, void *data) -{ - cmd->reply = "Read-only property"; - return 1; -} - static int bts_connection_status_trap_cb(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data) { struct ctrl_cmd *cmd; @@ -496,7 +474,7 @@ err: return 1; } -CTRL_CMD_DEFINE(bts_rf_state, "rf_state"); +CTRL_CMD_DEFINE_RO(bts_rf_state, "rf_state"); static int get_bts_rf_state(struct ctrl_cmd *cmd, void *data) { const char *oper, *admin, *policy; @@ -520,16 +498,6 @@ static int get_bts_rf_state(struct ctrl_cmd *cmd, void *data) return CTRL_CMD_REPLY; } -static int set_bts_rf_state(struct ctrl_cmd *cmd, void *data) -{ - cmd->reply = "set is unimplemented"; - return CTRL_CMD_ERROR; -} - -static int verify_bts_rf_state(struct ctrl_cmd *cmd, const char *value, void *data) -{ - return 0; -} CTRL_CMD_DEFINE(net_rf_lock, "rf_locked"); static int get_net_rf_lock(struct ctrl_cmd *cmd, void *data) -- 1.9.1 From jerlbeck at sysmocom.de Thu May 15 12:58:28 2014 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Thu, 15 May 2014 14:58:28 +0200 Subject: [PATCH] ctrl: Introduce a macro for read-only attributes and use it In-Reply-To: <1400145868-19050-1-git-send-email-holger@freyther.de> References: <1400145868-19050-1-git-send-email-holger@freyther.de> Message-ID: <5374B9F4.50602@sysmocom.de> That's much better that adding dummy functions manually. On 15.05.2014 11:24, Holger Freyther wrote: > From: Holger Hans Peter Freyther > > Certain attributes are read-only. Add a macro to make it more > easy to define those. > --- > --- a/openbsc/include/openbsc/control_cmd.h > +++ b/openbsc/include/openbsc/control_cmd.h > +#define CTRL_CMD_DEFINE_RO(cmdname, cmdstr) \ > +static int get_##cmdname(struct ctrl_cmd *cmd, void *data); \ > +static inline int set_##cmdname(struct ctrl_cmd *cmd, void *data) \ Why inline? We basically need the addresses of these functions. > +{ \ > + cmd->reply = "Read Only attribute"; \ > + return CTRL_CMD_ERROR; \ > +} \ > +static inline int verify_##cmdname(struct ctrl_cmd *cmd, const char *value, void *data) \ > +{ \ > + cmd->reply = "Read Only attribute"; \ > + return 1; \ > +} \ > +static struct ctrl_cmd_element cmd_##cmdname = { \ > + .name = cmdstr, \ > + .param = NULL, \ > + .get = &get_##cmdname, \ > + .set = &set_##cmdname, \ > + .verify = &verify_##cmdname, \ > +} It's quite some code duplication. What about something like the following (even if the resulting 'forward' declarations are somewhat senseless). This would even work with the ';' in the 'calling' code: #define CTRL_CMD_DEFINE_RO(cmdname, cmdstr) \ static int set_##cmdname(struct ctrl_cmd *cmd, void *data) \ { \ cmd->reply = "Read Only attribute"; \ return CTRL_CMD_ERROR; \ } \ static int verify_##cmdname(struct ctrl_cmd *cmd, const char *value, void *data) \ { \ cmd->reply = "Read Only attribute"; \ return 1; \ } \ CTRL_CMD_DEFINE(cmdname, cmdstr) Jacob -- - Jacob Erlbeck http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Schivelbeiner Str. 5 * 10439 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte From holger at freyther.de Thu May 15 13:58:11 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Thu, 15 May 2014 15:58:11 +0200 Subject: [PATCH] ctrl: Introduce a macro for read-only attributes and use it In-Reply-To: <5374B9F4.50602@sysmocom.de> References: <1400145868-19050-1-git-send-email-holger@freyther.de> <5374B9F4.50602@sysmocom.de> Message-ID: <20140515135811.GH26903@xiaoyu.lan> On Thu, May 15, 2014 at 02:58:28PM +0200, Jacob Erlbeck wrote: > Why inline? We basically need the addresses of these functions. Like it is done for most methods defined inside a header file. But you are right, we do not need the inline here. > It's quite some code duplication. What about something like the > following (even if the resulting 'forward' declarations are somewhat > senseless). This would even work with the ';' in the 'calling' code: > > #define CTRL_CMD_DEFINE_RO(cmdname, cmdstr) \ ... > CTRL_CMD_DEFINE(cmdname, cmdstr) Good idea, I have done that and cleaned it up a bit further. From ericcui at smart-nest.cn Fri May 16 07:53:09 2014 From: ericcui at smart-nest.cn (=?utf-8?B?5bSU5pmv6IGU?=) Date: Fri, 16 May 2014 15:53:09 +0800 Subject: what wrong? Message-ID: i cant find anything in your website,i just want to know how to use c++ to do this. -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: A340A6C0 at ECBF265F.E5C37553.jpg Type: image/jpeg Size: 171541 bytes Desc: not available URL: From ottawa712 at gmail.com Fri May 16 20:37:39 2014 From: ottawa712 at gmail.com (ottawa ottawa) Date: Fri, 16 May 2014 16:37:39 -0400 Subject: PDP deactivation on a particular cell phone--can anybody reply please Message-ID: Hi I any suggestion is welcome, I am bit stuck don't know how to proceed. regrads I am using OpenBSC/GPRS with nanoBTS. Thanks everybody for the great work. GPRS works well with many cell phone, but for particular cell phone its not working. I saw Olaf Schulz posting (subject: GPRS problems with Nokia Handsets dated 4th May 2012). Saw his pcap file and mine is similar too. Frank Mass suggested a patch to overcome this problem in his posting (subject gprs_llc.c foreighn TLLI is stored but not searched, dated 30 April 2012). I have implemented that patch but still not working. Can any body suggest something. Please find the osmo-sgsn trace <0011> gprs_bssgp.c:376 BSSGP TLLI=0xabfafd41 Rx UPLINK-UNITDATA <0012> gprs_llc.c:551 LLC SAPI=1 C FCS=0x76d7d9CMD=UI DATA <0012> gprs_llc.c:95 TLLI 0xabfafd41 is foreign, converting to local TLLI 0xebfafd41 <0012> gprs_llc.c:245 LLC RX: unknown TLLI 0xabfafd41, creating LLME on the fly <0011> gprs_bssgp.c:753 BSSGP BVCI=2 Rx Flow Control BVC <0011> gprs_bssgp.c:376 BSSGP TLLI=0xabfafd41 Rx UPLINK-UNITDATA <0012> gprs_llc.c:551 LLC SAPI=1 R FCS=0x57768eCMD=XID DATA <0011> gprs_bssgp.c:376 BSSGP TLLI=0xabfafd41 Rx UPLINK-UNITDATA <0012> gprs_llc.c:551 LLC SAPI=1 C FCS=0x9ab10aCMD=UI DATA <0012> gprs_llc.c:598 TLLI=abfafd41 dropping UI, N(U=0) not in window V(URV(UR:3). <0011> gprs_bssgp.c:753 BSSGP BVCI=2 Rx Flow Control BVC <0011> gprs_bssgp.c:753 BSSGP BVCI=2 Rx Flow Control BVC <0011> gprs_bssgp.c:376 BSSGP TLLI=0x7d3b00c1 Rx UPLINK-UNITDATA <0012> gprs_llc.c:551 LLC SAPI=1 C FCS=0xfd5011CMD=UI DATA <0012> gprs_llc.c:245 LLC RX: unknown TLLI 0x7d3b00c1, creating LLME on the fly <0011> gprs_bssgp.c:753 BSSGP BVCI=2 Rx Flow Control BVC <0011> gprs_bssgp.c:376 BSSGP TLLI=0x7d3b00c1 Rx UPLINK-UNITDATA <0012> gprs_llc.c:551 LLC SAPI=1 C FCS=0x11fb2fCMD=UI DATA <0011> gprs_bssgp.c:376 BSSGP TLLI=0x7d3b00c1 Rx UPLINK-UNITDATA <0012> gprs_llc.c:551 LLC SAPI=1 C FCS=0xea1c55CMD=UI DATA <0011> gprs_bssgp.c:753 BSSGP BVCI=2 Rx Flow Control BVC <0011> gprs_bssgp.c:753 BSSGP BVCI=2 Rx Flow Control BVC <0011> gprs_bssgp.c:376 BSSGP TLLI=0xe23c0990 Rx UPLINK-UNITDATA <0012> gprs_llc.c:551 LLC SAPI=1 C FCS=0x2a6a81CMD=UI DATA <000f> sgsn_libgtp.c:126 Create PDP Context <000f> sgsn_libgtp.c:379 libgtp cb_conf(type=16, cause=128, pdp=0x7feafc152320, cbp=0x6bcf50) <000f> sgsn_libgtp.c:265 Received CREATE PDP CTX CONF, cause=128(Request accepted) <0013> gprs_sndcp.c:297 SNSM-ACTIVATE.ind (lle=0x6bbe60 TLLI=e23c0990, SAPI=3, NSAPI=5) <0011> gprs_bssgp.c:753 BSSGP BVCI=2 Rx Flow Control BVC <0011> gprs_bssgp.c:753 BSSGP BVCI=2 Rx Flow Control BVC <0011> gprs_bssgp.c:753 BSSGP BVCI=2 Rx Flow Control BVC <0011> gprs_bssgp.c:376 BSSGP TLLI=0xe23c0990 Rx UPLINK-UNITDATA <0012> gprs_llc.c:551 LLC SAPI=1 C FCS=0x819789CMD=UI DATA <000f> sgsn_libgtp.c:212 Delete PDP Context <000f> sgsn_libgtp.c:402 PDP Context was deleted <000f> sgsn_libgtp.c:379 libgtp cb_conf(type=20, cause=128, pdp=(nil), cbp=0x6bcf50) <000f> sgsn_libgtp.c:321 Received DELETE PDP CTX CONF, cause=128(Request accepted) <0013> gprs_sndcp.c:320 SNSM-DEACTIVATE.ind (lle=0x6bbe60, TLLI=e23c0990, SAPI=3, NSAPI=5) John -------------- next part -------------- An HTML attachment was scrubbed... URL: From dchardware at gmail.com Sun May 18 21:55:19 2014 From: dchardware at gmail.com (Sipos Csaba) Date: Sun, 18 May 2014 23:55:19 +0200 Subject: SIM programmer and SIM cards to use with OpenBSC In-Reply-To: References: Message-ID: <845873559.20140518235519@freemail.hu> Hi, Can someone please advice me a cheap SIM programmer and programmable SIM cards that are compatible with pySim and can be used with OpenBSC? I found many offers on Ebay, but I don't know if there is a compatibility concern or anything I need to know. Thanks! BR, Csaba From rp.labs at gmx.ch Mon May 19 09:32:11 2014 From: rp.labs at gmx.ch (Labs) Date: Mon, 19 May 2014 11:32:11 +0200 Subject: SIM programmer and SIM cards to use with OpenBSC In-Reply-To: <845873559.20140518235519@freemail.hu> References: <845873559.20140518235519@freemail.hu> Message-ID: <924400D1-0CD7-4312-9B41-17764F678067@gmx.ch> Hello, Have a look on the sysmocom shop website. They are compatible with pysim and openbsc. Many of the ebay sims are low quality and after a few writes you will have issues with them. Sent from my iPad > On May 18, 2014, at 23:55, Sipos Csaba wrote: > > Hi, > > Can someone please advice me a cheap SIM programmer and programmable > SIM cards that are compatible with pySim and can be used with OpenBSC? > > I found many offers on Ebay, but I don't know if there is a > compatibility concern or anything I need to know. > > Thanks! > > BR, > Csaba > > From anayuso at sysmocom.de Mon May 19 17:22:55 2014 From: anayuso at sysmocom.de (Alvaro Neira Ayuso) Date: Mon, 19 May 2014 19:22:55 +0200 Subject: [libosmocore PATCH 1/3] abis_nm: Added the new tlv_definition abis_nm_osmo_att_tlvdef in the abis header Message-ID: <1400520175-14962-1-git-send-email-anayuso@sysmocom.de> From: ?lvaro Neira Ayuso Signed-off-by: Alvaro Neira Ayuso --- include/osmocom/gsm/abis_nm.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/osmocom/gsm/abis_nm.h b/include/osmocom/gsm/abis_nm.h index 4682ead..86b97eb 100644 --- a/include/osmocom/gsm/abis_nm.h +++ b/include/osmocom/gsm/abis_nm.h @@ -30,6 +30,7 @@ extern const struct tlv_definition abis_nm_att_tlvdef; const char *abis_nm_opstate_name(uint8_t os); const char *abis_nm_avail_name(uint8_t avail); const char *abis_nm_test_name(uint8_t test); +extern const struct tlv_definition abis_nm_osmo_att_tlvdef; /*! \brief write a human-readable OML header to the debug log * \param[in] ss Logging sub-system -- 1.7.10.4 From anayuso at sysmocom.de Mon May 19 17:25:53 2014 From: anayuso at sysmocom.de (Alvaro Neira Ayuso) Date: Mon, 19 May 2014 19:25:53 +0200 Subject: [osmo-bts PATCH 2/3] sysmobts/sysmobts-mgr: Changed Reduce Power attribute and the tlv definition Message-ID: <1400520353-15062-1-git-send-email-anayuso@sysmocom.de> From: ?lvaro Neira Ayuso This patch is for changing the code for having consistency with the patch of libosmocore: Fix introducing osmocom speficic OML attributes 5b5650f3de0213a459b4184bab3ab2d0d833c4a4 For using the new tlv definition structure abis_nm_osmo_att_tlvdef and change the attribute NM_ATT_O_REDUCEPOWER to NM_ATT_OSMO_REDUCEPOWER. Signed-off-by: Alvaro Neira Ayuso --- src/osmo-bts-sysmo/main.c | 6 +++--- src/osmo-bts-sysmo/misc/sysmobts_misc.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/osmo-bts-sysmo/main.c b/src/osmo-bts-sysmo/main.c index 2c13a9c..60312b8 100644 --- a/src/osmo-bts-sysmo/main.c +++ b/src/osmo-bts-sysmo/main.c @@ -296,7 +296,7 @@ static int write_pid_file(char *procname) } #define oml_tlv_parse(dec, buf, len) \ - tlv_parse(dec, &abis_nm_att_tlvdef, buf, len, 0, 0) + tlv_parse(dec, &abis_nm_osmo_att_tlvdef, buf, len, 0, 0) static int send_oml_fom_ack_nack(int fd_unix, struct msgb *old_msg, uint8_t cause, int is_manuf) @@ -377,9 +377,9 @@ static int take_reduce_power(struct msgb *msg) return -1; } - if (TLVP_PRESENT(&tlv_out, NM_ATT_O_REDUCEPOWER)) + if (TLVP_PRESENT(&tlv_out, NM_ATT_OSMO_REDUCEPOWER)) recv_reduce_power = *TLVP_VAL(&tlv_out, - NM_ATT_O_REDUCEPOWER); + NM_ATT_OSMO_REDUCEPOWER); else return -1; diff --git a/src/osmo-bts-sysmo/misc/sysmobts_misc.c b/src/osmo-bts-sysmo/misc/sysmobts_misc.c index 6277a6b..5a52005 100644 --- a/src/osmo-bts-sysmo/misc/sysmobts_misc.c +++ b/src/osmo-bts-sysmo/misc/sysmobts_misc.c @@ -142,7 +142,7 @@ int send_manufacturer_reduce_msg(int fd_unix, int reduce_power, int trx_nr) add_oml_hdr_msg(msg, NM_MT_SET_RADIO_ATTR, 2, 0, trx_nr, 255, 1); - msgb_tv_put(msg, NM_ATT_O_REDUCEPOWER, reduce_power); + msgb_tv_put(msg, NM_ATT_OSMO_REDUCEPOWER, reduce_power); prepend_oml_ipa_header(msg); -- 1.7.10.4 From anayuso at sysmocom.de Tue May 20 05:34:16 2014 From: anayuso at sysmocom.de (Alvaro Neira Ayuso) Date: Tue, 20 May 2014 07:34:16 +0200 Subject: [libosmocore PATCH 1/5] abis_nm: Added the new tlv_definition abis_nm_osmo_att_tlvdef in the abis header Message-ID: <1400564056-8970-1-git-send-email-anayuso@sysmocom.de> From: ?lvaro Neira Ayuso Signed-off-by: Alvaro Neira Ayuso --- include/osmocom/gsm/abis_nm.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/osmocom/gsm/abis_nm.h b/include/osmocom/gsm/abis_nm.h index 4682ead..86b97eb 100644 --- a/include/osmocom/gsm/abis_nm.h +++ b/include/osmocom/gsm/abis_nm.h @@ -30,6 +30,7 @@ extern const struct tlv_definition abis_nm_att_tlvdef; const char *abis_nm_opstate_name(uint8_t os); const char *abis_nm_avail_name(uint8_t avail); const char *abis_nm_test_name(uint8_t test); +extern const struct tlv_definition abis_nm_osmo_att_tlvdef; /*! \brief write a human-readable OML header to the debug log * \param[in] ss Logging sub-system -- 1.7.10.4 From hwelte at sysmocom.de Tue May 20 06:12:21 2014 From: hwelte at sysmocom.de (Harald Welte) Date: Tue, 20 May 2014 08:12:21 +0200 Subject: [libosmocore PATCH 1/5] abis_nm: Added the new tlv_definition abis_nm_osmo_att_tlvdef in the abis header In-Reply-To: <1400564056-8970-1-git-send-email-anayuso@sysmocom.de> References: <1400564056-8970-1-git-send-email-anayuso@sysmocom.de> Message-ID: <20140520061221.GS14533@nataraja> Hi Alvaro, On Tue, May 20, 2014 at 07:34:16AM +0200, Alvaro Neira Ayuso wrote: > +extern const struct tlv_definition abis_nm_osmo_att_tlvdef; thanks, applied. Regards, Harald -- - Harald Welte http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Schivelbeiner Str. 5 * 10439 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte From holger at freyther.de Tue May 20 06:45:35 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Tue, 20 May 2014 08:45:35 +0200 Subject: [libosmocore PATCH 1/5] abis_nm: Added the new tlv_definition abis_nm_osmo_att_tlvdef in the abis header In-Reply-To: <1400564056-8970-1-git-send-email-anayuso@sysmocom.de> References: <1400564056-8970-1-git-send-email-anayuso@sysmocom.de> Message-ID: <20140520064535.GL29651@xiaoyu.lan> On Tue, May 20, 2014 at 07:34:16AM +0200, Alvaro Neira Ayuso wrote: Hi, in the subject you are using past tense ("Added") in general one will use the imperative/present tense. A search points me to this file in the git sources: http://git.kernel.org/cgit/git/git.git/tree/Documentation/SubmittingPatches?id=HEAD " Describe your changes in imperative mood, e.g. "make xyzzy do frotz" instead of "[This patch] makes xyzzy do frotz" or "[I] changed xyzzy to do frotz", as if you are giving orders to the codebase to change its behaviour. Try to make sure your explanation can be understood without external resources. Instead of giving a URL to a mailing list archive, summarize the relevant points of the discussion. " I will re-write the subject. cheers holger From alvaroneay at gmail.com Tue May 20 06:50:51 2014 From: alvaroneay at gmail.com (=?ISO-8859-1?Q?=C1lvaro_Neira_Ayuso?=) Date: Tue, 20 May 2014 08:50:51 +0200 Subject: [libosmocore PATCH 1/5] abis_nm: Added the new tlv_definition abis_nm_osmo_att_tlvdef in the abis header In-Reply-To: <20140520064535.GL29651@xiaoyu.lan> References: <1400564056-8970-1-git-send-email-anayuso@sysmocom.de> <20140520064535.GL29651@xiaoyu.lan> Message-ID: <537AFB4B.3090208@gmail.com> Good Morning El 20/05/14 08:45, Holger Hans Peter Freyther escribi?: > On Tue, May 20, 2014 at 07:34:16AM +0200, Alvaro Neira Ayuso wrote: > > Hi, > > in the subject you are using past tense ("Added") in general one > will use the imperative/present tense. A search points me to this > file in the git sources: > > http://git.kernel.org/cgit/git/git.git/tree/Documentation/SubmittingPatches?id=HEAD > > " > Describe your changes in imperative mood, e.g. "make xyzzy do frotz" > instead of "[This patch] makes xyzzy do frotz" or "[I] changed xyzzy > to do frotz", as if you are giving orders to the codebase to change > its behaviour. Try to make sure your explanation can be understood > without external resources. Instead of giving a URL to a mailing list > archive, summarize the relevant points of the discussion. > " > > I will re-write the subject. I didn't know that. Thanks Holger. I'm going to take a look and the next patches, I'm going to write the subject like you have explained me. Cheers ?lvaro From anayuso at sysmocom.de Tue May 20 05:40:47 2014 From: anayuso at sysmocom.de (Alvaro Neira Ayuso) Date: Tue, 20 May 2014 07:40:47 +0200 Subject: [osmo-bts PATCH 2/5] moved out the ipa header sanity check in check_oml_msg Message-ID: <1400564447-9600-1-git-send-email-anayuso@sysmocom.de> From: ?lvaro Neira Ayuso I have split the function check_oml_msg, in two functions. One for checking if the ipa header is well-formed and in check_oml_msg, I have removed this code for using in the future the function check_oml_msg for passing a sanity check to oml message without ipa header. Signed-off-by: Alvaro Neira Ayuso --- src/osmo-bts-sysmo/main.c | 11 +++++++++- src/osmo-bts-sysmo/utils.c | 50 ++++++++++++++++++++++++-------------------- src/osmo-bts-sysmo/utils.h | 1 + 3 files changed, 38 insertions(+), 24 deletions(-) diff --git a/src/osmo-bts-sysmo/main.c b/src/osmo-bts-sysmo/main.c index bd6a181..797f174 100644 --- a/src/osmo-bts-sysmo/main.c +++ b/src/osmo-bts-sysmo/main.c @@ -317,7 +317,16 @@ static int read_sock(struct osmo_fd *fd, unsigned int what) msgb_put(msg, rc); - if (check_oml_msg(msg) < 0) { + rc = check_ipa_header(msg); + if (rc < 0) { + LOGP(DL1C, LOGL_ERROR, "Malformed receive message: Ipa hdr\n"); + goto err; + } + + msgb_pull(msg, sizeof(struct ipaccess_head)); + + rc = check_oml_msg(msg); + if (rc < 0) { LOGP(DL1C, LOGL_ERROR, "Malformed receive message\n"); goto err; } diff --git a/src/osmo-bts-sysmo/utils.c b/src/osmo-bts-sysmo/utils.c index 2da1228..1fa5796 100644 --- a/src/osmo-bts-sysmo/utils.c +++ b/src/osmo-bts-sysmo/utils.c @@ -181,33 +181,10 @@ void prepend_oml_ipa_header(struct msgb *msg) int check_oml_msg(struct msgb *msg) { - struct ipaccess_head *hh; struct abis_om_hdr *omh; int abis_oml_hdr_len; char label_id[255]; - if (msg->len < sizeof(struct ipaccess_head)) { - LOGP(DL1C, LOGL_ERROR, "Ipa header insufficient space %d %d\n", - msg->len, sizeof(struct ipaccess_head)); - return -1; - } - - hh = (struct ipaccess_head *)msg->data; - - if (hh->proto != IPAC_PROTO_OML) { - LOGP(DL1C, LOGL_ERROR, "Incorrect ipa header protocol %x %x\n", - hh->proto, IPAC_PROTO_OML); - return -1; - } - - if (ntohs(hh->len) != msg->len - sizeof(struct ipaccess_head)) { - LOGP(DL1C, LOGL_ERROR, "Incorrect ipa header msg size %d %d\n", - ntohs(hh->len), msg->len - sizeof(struct ipaccess_head)); - return -1; - } - - msgb_pull(msg, sizeof(struct ipaccess_head)); - abis_oml_hdr_len = sizeof(struct abis_om_hdr); if (msg->len < abis_oml_hdr_len) { @@ -287,6 +264,33 @@ int check_oml_msg(struct msgb *msg) return 0; } +int check_ipa_header(struct msgb *msg) +{ + struct ipaccess_head *hh; + + if (msg->len < sizeof(struct ipaccess_head)) { + LOGP(DL1C, LOGL_ERROR, "Ipa header insufficient space %d %d\n", + msg->len, sizeof(struct ipaccess_head)); + return -1; + } + + hh = (struct ipaccess_head *)msg->data; + + if (hh->proto != IPAC_PROTO_OML) { + LOGP(DL1C, LOGL_ERROR, "Incorrect ipa header protocol %x %x\n", + hh->proto, IPAC_PROTO_OML); + return -1; + } + + if (ntohs(hh->len) != msg->len - sizeof(struct ipaccess_head)) { + LOGP(DL1C, LOGL_ERROR, "Incorrect ipa header msg size %d %d\n", + ntohs(hh->len), msg->len - sizeof(struct ipaccess_head)); + return -1; + } + + return 0; +} + int add_manufacturer_id_label(struct msgb *msg, int manuf_type_id) { uint8_t *manuf; diff --git a/src/osmo-bts-sysmo/utils.h b/src/osmo-bts-sysmo/utils.h index 85a5e88..4f2293a 100644 --- a/src/osmo-bts-sysmo/utils.h +++ b/src/osmo-bts-sysmo/utils.h @@ -29,4 +29,5 @@ int add_manufacturer_id_label(struct msgb *msg, int manuf_type_id); void prepend_oml_ipa_header(struct msgb *msg); int check_oml_msg(struct msgb *msg); +int check_ipa_header(struct msgb *msg); #endif -- 1.7.10.4 From holger at freyther.de Tue May 20 07:03:04 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Tue, 20 May 2014 09:03:04 +0200 Subject: [osmo-bts PATCH 2/5] moved out the ipa header sanity check in check_oml_msg In-Reply-To: <1400564447-9600-1-git-send-email-anayuso@sysmocom.de> References: <1400564447-9600-1-git-send-email-anayuso@sysmocom.de> Message-ID: <20140520070304.GN29651@xiaoyu.lan> On Tue, May 20, 2014 at 07:40:47AM +0200, Alvaro Neira Ayuso wrote: Hi, could you please follow up with another clean-up? Could you use msg->l2h and msgb_l2len for the IPA header and set msg->l3h and use msgb_l3len for the OML message? This way you can omit the the msgb_pull. thanks holger From anayuso at sysmocom.de Tue May 20 05:42:24 2014 From: anayuso at sysmocom.de (Alvaro Neira Ayuso) Date: Tue, 20 May 2014 07:42:24 +0200 Subject: [osmo-bts PATCH 3/5] utils: Changed the function check_oml_message for returning message vendor type Message-ID: <1400564544-9709-1-git-send-email-anayuso@sysmocom.de> From: ?lvaro Neira Ayuso Added some changes for returning the vendor type of message that we have checked. We are going to return OML, Manufacturer O&M Ipaccess message or Manufacturer O&M osmocom message. BTW, I have fixed a wrong use of sizeof in the code that I have modified. Signed-off-by: Alvaro Neira Ayuso --- src/osmo-bts-sysmo/utils.c | 14 ++++++++------ src/osmo-bts-sysmo/utils.h | 6 ++++++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/osmo-bts-sysmo/utils.c b/src/osmo-bts-sysmo/utils.c index 1fa5796..e676a3c 100644 --- a/src/osmo-bts-sysmo/utils.c +++ b/src/osmo-bts-sysmo/utils.c @@ -245,15 +245,17 @@ int check_oml_msg(struct msgb *msg) if (omh->mdisc == ABIS_OM_MDISC_MANUF) { strncpy(label_id, (const char *) msg->l3h + 1, - sizeof(ipaccess_magic) + 1); + sizeof(ipaccess_magic)); if (strncmp(ipaccess_magic, label_id, - sizeof(ipaccess_magic) + 1) == 0) + sizeof(ipaccess_magic)) == 0) { msg->l3h = msg->l3h + sizeof(ipaccess_magic) + 1; - else if (strncmp(osmocom_magic, label_id, - sizeof(osmocom_magic) + 1) == 0) + return MANUFACTURER_MSG_IPA_TYPE; + } else if (strncmp(osmocom_magic, label_id, + sizeof(osmocom_magic)) == 0) { msg->l3h = msg->l3h + sizeof(osmocom_magic) + 1; - else { + return MANUFACTURER_MSG_OSMO_TYPE; + } else { msg->l3h = NULL; LOGP(DL1C, LOGL_ERROR, "Manuf Label Unknown %s\n", label_id); @@ -261,7 +263,7 @@ int check_oml_msg(struct msgb *msg) } } - return 0; + return OML_MSG_TYPE; } int check_ipa_header(struct msgb *msg) diff --git a/src/osmo-bts-sysmo/utils.h b/src/osmo-bts-sysmo/utils.h index 4f2293a..dbbe443 100644 --- a/src/osmo-bts-sysmo/utils.h +++ b/src/osmo-bts-sysmo/utils.h @@ -21,6 +21,12 @@ enum manuf_type_id { OSMOCOM_MANUF_ID, }; +enum check_message_type { + OML_MSG_TYPE, + MANUFACTURER_MSG_IPA_TYPE, + MANUFACTURER_MSG_OSMO_TYPE, +}; + static const char osmocom_magic[] = "org.osmocom"; static const char ipaccess_magic[] = "com.ipaccess"; -- 1.7.10.4 From holger at freyther.de Tue May 20 07:04:31 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Tue, 20 May 2014 09:04:31 +0200 Subject: [osmo-bts PATCH 3/5] utils: Changed the function check_oml_message for returning message vendor type In-Reply-To: <1400564544-9709-1-git-send-email-anayuso@sysmocom.de> References: <1400564544-9709-1-git-send-email-anayuso@sysmocom.de> Message-ID: <20140520070431.GO29651@xiaoyu.lan> On Tue, May 20, 2014 at 07:42:24AM +0200, Alvaro Neira Ayuso wrote: > BTW, I have fixed a wrong use of sizeof in the code that I have modified. Please make a separate patch for this fix. It sneaked through my review but deserves a fix by itself. From holger at freyther.de Tue May 20 07:10:28 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Tue, 20 May 2014 09:10:28 +0200 Subject: [osmo-bts PATCH 3/5] utils: Changed the function check_oml_message for returning message vendor type In-Reply-To: <1400564544-9709-1-git-send-email-anayuso@sysmocom.de> References: <1400564544-9709-1-git-send-email-anayuso@sysmocom.de> Message-ID: <20140520071028.GQ29651@xiaoyu.lan> On Tue, May 20, 2014 at 07:42:24AM +0200, Alvaro Neira Ayuso wrote: > +enum check_message_type { > + OML_MSG_TYPE, > + MANUFACTURER_MSG_IPA_TYPE, > + MANUFACTURER_MSG_OSMO_TYPE, In general elements of an enum have a common prefix. I will change this here. From anayuso at sysmocom.de Tue May 20 05:44:07 2014 From: anayuso at sysmocom.de (Alvaro Neira Ayuso) Date: Tue, 20 May 2014 07:44:07 +0200 Subject: [osmo-bts PATCH 4/5] utils: Used the enum manuf_type_id in the parameter of add_manufacturer_id_label Message-ID: <1400564647-9794-1-git-send-email-anayuso@sysmocom.de> From: ?lvaro Neira Ayuso Signed-off-by: Alvaro Neira Ayuso --- src/osmo-bts-sysmo/utils.c | 4 ++-- src/osmo-bts-sysmo/utils.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/osmo-bts-sysmo/utils.c b/src/osmo-bts-sysmo/utils.c index e676a3c..8652588 100644 --- a/src/osmo-bts-sysmo/utils.c +++ b/src/osmo-bts-sysmo/utils.c @@ -293,11 +293,11 @@ int check_ipa_header(struct msgb *msg) return 0; } -int add_manufacturer_id_label(struct msgb *msg, int manuf_type_id) +int add_manufacturer_id_label(struct msgb *msg, enum manuf_type_id type_id) { uint8_t *manuf; - switch (manuf_type_id) { + switch (type_id) { case IPACCESS_MANUF_ID: manuf = msgb_push(msg, 1 + sizeof(ipaccess_magic)); manuf[0] = sizeof(ipaccess_magic); diff --git a/src/osmo-bts-sysmo/utils.h b/src/osmo-bts-sysmo/utils.h index dbbe443..a629ac1 100644 --- a/src/osmo-bts-sysmo/utils.h +++ b/src/osmo-bts-sysmo/utils.h @@ -30,7 +30,7 @@ enum check_message_type { static const char osmocom_magic[] = "org.osmocom"; static const char ipaccess_magic[] = "com.ipaccess"; -int add_manufacturer_id_label(struct msgb *msg, int manuf_type_id); +int add_manufacturer_id_label(struct msgb *msg, enum manuf_type_id type_id); void prepend_oml_ipa_header(struct msgb *msg); -- 1.7.10.4 From anayuso at sysmocom.de Tue May 20 16:16:56 2014 From: anayuso at sysmocom.de (Alvaro Neira Ayuso) Date: Tue, 20 May 2014 18:16:56 +0200 Subject: [osmo-bts PATCH 1/2] oml: Add support com.ipacces and org.osmocom manufacturer type Message-ID: <1400602616-24671-1-git-send-email-anayuso@sysmocom.de> From: ?lvaro Neira Ayuso This patch allows to add the osmocom manufacturer id label in the manufacturer message. Before of this patch, everytime we have added ipaccess because we had only one kind of manufacturer message. And I have moved the code that we have used for adding this manufacturer ID label to the function oml_fom_ack_nack because we only add the manufacturer Id label in this function now. Signed-off-by: Alvaro Neira Ayuso --- src/common/oml.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/common/oml.c b/src/common/oml.c index b7c12f7..42e4e80 100644 --- a/src/common/oml.c +++ b/src/common/oml.c @@ -93,6 +93,7 @@ static struct tlv_definition abis_nm_att_tlvdef_ipa = { /* ip.access nanoBTS specific commands */ static const char ipaccess_magic[] = "com.ipaccess"; +static const char osmocom_magic[] = "org.osmocom"; static int oml_ipa_set_attr(struct gsm_bts *bts, struct msgb *msg); /* @@ -163,13 +164,6 @@ int oml_send_msg(struct msgb *msg, int is_manuf) { struct abis_om_hdr *omh; - if (is_manuf) { - /* length byte, string + 0 termination */ - uint8_t *manuf = msgb_push(msg, 1 + sizeof(ipaccess_magic)); - manuf[0] = strlen(ipaccess_magic)+1; - memcpy(manuf+1, ipaccess_magic, strlen(ipaccess_magic)); - } - /* Push the main OML header and send it off */ omh = (struct abis_om_hdr *) msgb_push(msg, sizeof(*omh)); if (is_manuf) @@ -321,6 +315,7 @@ int oml_fom_ack_nack(struct msgb *old_msg, uint8_t cause) struct msgb *msg; struct abis_om_fom_hdr *foh; int is_manuf = 0; + uint8_t *manuf; msg = oml_msgb_alloc(); if (!msg) @@ -349,6 +344,24 @@ int oml_fom_ack_nack(struct msgb *old_msg, uint8_t cause) foh->msg_type++; /* ack */ } + if (is_manuf) { + if (strncmp(osmocom_magic, (const char *)old_oh->data + 1, + sizeof(osmocom_magic)) == 0) { + manuf = msgb_push(msg, 1 + sizeof(osmocom_magic)); + manuf[0] = sizeof(osmocom_magic); + memcpy(manuf+1, osmocom_magic, sizeof(osmocom_magic)); + } else if (strncmp(ipaccess_magic, + (const char *)old_oh->data + 1, + sizeof(ipaccess_magic)) == 0) { + manuf = msgb_push(msg, 1 + sizeof(ipaccess_magic)); + manuf[0] = sizeof(ipaccess_magic); + memcpy(manuf+1, ipaccess_magic, sizeof(ipaccess_magic)); + } else { + LOGP(DOML, LOGL_ERROR, "Unknown manufacturer label.\n"); + return -1; + } + } + return oml_send_msg(msg, is_manuf); } -- 1.7.10.4 From anayuso at sysmocom.de Tue May 20 16:21:22 2014 From: anayuso at sysmocom.de (Alvaro Neira Ayuso) Date: Tue, 20 May 2014 18:21:22 +0200 Subject: [osmo-bts PATCH 2/2] oml: Allow to send ACK/NACK message through a different socket. Message-ID: <1400602882-24801-1-git-send-email-anayuso@sysmocom.de> From: ?lvaro Neira Ayuso This patch, I have done something for reach my goal. I have changed the function oml_fom_ack_nack for returning the ACK/NACK message that we have created. Later I have splited the function send_oml_msg in two different function. One for send the oml messages with abis (send_oml_msg) and another for append the fom header in the message. Before of that we always add the fom before of send the message with Abis always. Later I have modified the code for using the new functions. Signed-off-by: Alvaro Neira Ayuso --- include/osmo-bts/oml.h | 4 +- src/common/oml.c | 103 ++++++++++++++++++++++++++++++---------------- src/osmo-bts-sysmo/oml.c | 2 +- 3 files changed, 70 insertions(+), 39 deletions(-) diff --git a/include/osmo-bts/oml.h b/include/osmo-bts/oml.h index 4281fd3..1e697d6 100644 --- a/include/osmo-bts/oml.h +++ b/include/osmo-bts/oml.h @@ -5,7 +5,7 @@ int oml_init(void); int down_oml(struct gsm_bts *bts, struct msgb *msg); struct msgb *oml_msgb_alloc(void); -int oml_send_msg(struct msgb *msg, int is_mauf); +int oml_send_msg(struct msgb *msg); int oml_mo_send_msg(struct gsm_abis_mo *mo, struct msgb *msg, uint8_t msg_type); int oml_mo_opstart_ack(struct gsm_abis_mo *mo); int oml_mo_opstart_nack(struct gsm_abis_mo *mo, uint8_t nack_cause); @@ -27,7 +27,7 @@ int oml_tx_state_changed(struct gsm_abis_mo *mo); int oml_mo_tx_sw_act_rep(struct gsm_abis_mo *mo); -int oml_fom_ack_nack(struct msgb *old_msg, uint8_t cause); +struct msgb *oml_fom_ack_nack(struct msgb *old_msg, uint8_t cause); int oml_mo_fom_ack_nack(struct gsm_abis_mo *mo, uint8_t orig_msg_type, uint8_t cause); diff --git a/src/common/oml.c b/src/common/oml.c index 42e4e80..ba3323b 100644 --- a/src/common/oml.c +++ b/src/common/oml.c @@ -160,7 +160,7 @@ struct msgb *oml_msgb_alloc(void) return msgb_alloc_headroom(1024, 128, "OML"); } -int oml_send_msg(struct msgb *msg, int is_manuf) +void oml_append_fom_hdr(struct msgb *msg, int is_manuf) { struct abis_om_hdr *omh; @@ -175,7 +175,10 @@ int oml_send_msg(struct msgb *msg, int is_manuf) omh->length = msgb_l3len(msg); msg->l2h = (uint8_t *)omh; +} +int oml_send_msg(struct msgb *msg) +{ return abis_oml_sendmsg(msg); } @@ -192,7 +195,9 @@ int oml_mo_send_msg(struct gsm_abis_mo *mo, struct msgb *msg, uint8_t msg_type) /* FIXME: This assumption may not always be correct */ msg->trx = mo->bts->c0; - return oml_send_msg(msg, 0); + oml_append_fom_hdr(msg, 0); + + return oml_send_msg(msg); } /* FIXME: move to gsm_data_shared */ @@ -308,7 +313,7 @@ int oml_mo_opstart_nack(struct gsm_abis_mo *mo, uint8_t nack_cause) return oml_mo_fom_ack_nack(mo, NM_MT_OPSTART, nack_cause); } -int oml_fom_ack_nack(struct msgb *old_msg, uint8_t cause) +struct msgb *oml_fom_ack_nack(struct msgb *old_msg, uint8_t cause) { struct abis_om_hdr *old_oh = msgb_l2(old_msg); struct abis_om_fom_hdr *old_foh = msgb_l3(old_msg); @@ -318,8 +323,10 @@ int oml_fom_ack_nack(struct msgb *old_msg, uint8_t cause) uint8_t *manuf; msg = oml_msgb_alloc(); - if (!msg) - return -ENOMEM; + if (!msg) { + LOGP(DOML, LOGL_ERROR, "Creating oml ACK/NACK msg.\n"); + return NULL; + } /* make sure to respond with MANUF if request was MANUF */ if (old_oh->mdisc == ABIS_OM_MDISC_MANUF) @@ -357,12 +364,15 @@ int oml_fom_ack_nack(struct msgb *old_msg, uint8_t cause) manuf[0] = sizeof(ipaccess_magic); memcpy(manuf+1, ipaccess_magic, sizeof(ipaccess_magic)); } else { + msgb_free(msg); LOGP(DOML, LOGL_ERROR, "Unknown manufacturer label.\n"); - return -1; + return NULL; } } - return oml_send_msg(msg, is_manuf); + oml_append_fom_hdr(msg, is_manuf); + + return msg; } /* @@ -420,7 +430,8 @@ static int oml_rx_set_bts_attr(struct gsm_bts *bts, struct msgb *msg) rc = oml_tlv_parse(&tp, foh->data, msgb_l3len(msg) - sizeof(*foh)); if (rc < 0) - return oml_fom_ack_nack(msg, NM_NACK_INCORR_STRUCT); + return oml_send_msg(oml_fom_ack_nack(msg, + NM_NACK_INCORR_STRUCT)); /* Test for globally unsupported stuff here */ if (TLVP_PRESENT(&tp, NM_ATT_BCCH_ARFCN)) { @@ -433,12 +444,14 @@ static int oml_rx_set_bts_attr(struct gsm_bts *bts, struct msgb *msg) if (arfcn > 1024) { LOGP(DOML, LOGL_NOTICE, "Given ARFCN %d is not supported.\n", arfcn); - return oml_fom_ack_nack(msg, NM_NACK_FREQ_NOTAVAIL); + return oml_send_msg(oml_fom_ack_nack(msg, + NM_NACK_FREQ_NOTAVAIL)); } } /* 9.4.52 Starting Time */ if (TLVP_PRESENT(&tp, NM_ATT_START_TIME)) { - return oml_fom_ack_nack(msg, NM_NACK_SPEC_IMPL_NOTSUPP); + return oml_send_msg(oml_fom_ack_nack(msg, + NM_NACK_SPEC_IMPL_NOTSUPP)); } /* merge existing BTS attributes with new attributes */ @@ -449,7 +462,7 @@ static int oml_rx_set_bts_attr(struct gsm_bts *bts, struct msgb *msg) rc = bts_model_check_oml(bts, foh->msg_type, bts->mo.nm_attr, tp_merged, bts); if (rc < 0) { talloc_free(tp_merged); - return oml_fom_ack_nack(msg, -rc); + return oml_send_msg(oml_fom_ack_nack(msg, -rc)); } /* Success: replace old BTS attributes with new */ @@ -479,7 +492,8 @@ static int oml_rx_set_bts_attr(struct gsm_bts *bts, struct msgb *msg) LOGP(DOML, LOGL_NOTICE, "Given Conn. Failure Criterion " "not supported. Please use critetion 0x01 with " "RADIO_LINK_TIMEOUT value of 4..64\n"); - return oml_fom_ack_nack(msg, NM_NACK_PARAM_RANGE); + return oml_send_msg(oml_fom_ack_nack(msg, + NM_NACK_PARAM_RANGE)); } btsb->radio_link_timeout = val[1]; } @@ -527,7 +541,8 @@ static int oml_rx_set_bts_attr(struct gsm_bts *bts, struct msgb *msg) if (t3105 == 0) { LOGP(DOML, LOGL_NOTICE, "T3105 must have a value != 0.\n"); - return oml_fom_ack_nack(msg, NM_NACK_PARAM_RANGE); + return oml_send_msg(oml_fom_ack_nack(msg, + NM_NACK_PARAM_RANGE)); } btsb->t3105_ms = t3105 * 10; } @@ -560,7 +575,8 @@ static int oml_rx_set_radio_attr(struct gsm_bts_trx *trx, struct msgb *msg) rc = oml_tlv_parse(&tp, foh->data, msgb_l3len(msg) - sizeof(*foh)); if (rc < 0) - return oml_fom_ack_nack(msg, NM_NACK_INCORR_STRUCT); + return oml_send_msg(oml_fom_ack_nack(msg, + NM_NACK_INCORR_STRUCT)); /* merge existing BTS attributes with new attributes */ tp_merged = tlvp_copy(trx->mo.nm_attr, trx->bts); @@ -570,7 +586,7 @@ static int oml_rx_set_radio_attr(struct gsm_bts_trx *trx, struct msgb *msg) rc = bts_model_check_oml(trx->bts, foh->msg_type, trx->mo.nm_attr, tp_merged, trx); if (rc < 0) { talloc_free(tp_merged); - return oml_fom_ack_nack(msg, -rc); + return oml_send_msg(oml_fom_ack_nack(msg, -rc)); } /* Success: replace old BTS attributes with new */ @@ -666,19 +682,22 @@ static int oml_rx_set_chan_attr(struct gsm_bts_trx_ts *ts, struct msgb *msg) rc = oml_tlv_parse(&tp, foh->data, msgb_l3len(msg) - sizeof(*foh)); if (rc < 0) - return oml_fom_ack_nack(msg, NM_NACK_INCORR_STRUCT); + return oml_send_msg(oml_fom_ack_nack(msg, + NM_NACK_INCORR_STRUCT)); /* 9.4.21 HSN... */ /* 9.4.27 MAIO */ if (TLVP_PRESENT(&tp, NM_ATT_HSN) || TLVP_PRESENT(&tp, NM_ATT_MAIO)) { LOGP(DOML, LOGL_NOTICE, "SET CHAN ATTR: Frequency hopping not supported.\n"); - return oml_fom_ack_nack(msg, NM_NACK_SPEC_IMPL_NOTSUPP); + return oml_send_msg(oml_fom_ack_nack(msg, + NM_NACK_SPEC_IMPL_NOTSUPP)); } /* 9.4.52 Starting Time */ if (TLVP_PRESENT(&tp, NM_ATT_START_TIME)) { LOGP(DOML, LOGL_NOTICE, "SET CHAN ATTR: Starting time not supported.\n"); - return oml_fom_ack_nack(msg, NM_NACK_SPEC_IMPL_NOTSUPP); + return oml_send_msg(oml_fom_ack_nack(msg, + NM_NACK_SPEC_IMPL_NOTSUPP)); } /* merge existing BTS attributes with new attributes */ @@ -690,7 +709,7 @@ static int oml_rx_set_chan_attr(struct gsm_bts_trx_ts *ts, struct msgb *msg) if (rc < 0) { talloc_free(tp_merged); /* Send NACK */ - return oml_fom_ack_nack(msg, -rc); + return oml_send_msg(oml_fom_ack_nack(msg, -rc)); } /* Success: replace old BTS attributes with new */ @@ -734,7 +753,8 @@ static int oml_rx_opstart(struct gsm_bts *bts, struct msgb *msg) mo = gsm_objclass2mo(bts, foh->obj_class, &foh->obj_inst); obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst); if (!mo || !obj) - return oml_fom_ack_nack(msg, NM_NACK_OBJINST_UNKN); + return oml_send_msg(oml_fom_ack_nack(msg, + NM_NACK_OBJINST_UNKN)); /* Step 2: Do some global dependency/consistency checking */ if (mo->nm_state.operational == NM_OPSTATE_ENABLED) { @@ -761,12 +781,14 @@ static int oml_rx_chg_adm_state(struct gsm_bts *bts, struct msgb *msg) rc = oml_tlv_parse(&tp, foh->data, msgb_l3len(msg) - sizeof(*foh)); if (rc < 0) { LOGP(DOML, LOGL_ERROR, "Rx CHG ADM STATE: error during TLV parse\n"); - return oml_fom_ack_nack(msg, NM_NACK_INCORR_STRUCT); + return oml_send_msg(oml_fom_ack_nack(msg, + NM_NACK_INCORR_STRUCT)); } if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) { LOGP(DOML, LOGL_ERROR, "Rx CHG ADM STATE: no ADM state attribute\n"); - return oml_fom_ack_nack(msg, NM_NACK_INCORR_STRUCT); + return oml_send_msg(oml_fom_ack_nack(msg, + NM_NACK_INCORR_STRUCT)); } adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE); @@ -775,7 +797,8 @@ static int oml_rx_chg_adm_state(struct gsm_bts *bts, struct msgb *msg) mo = gsm_objclass2mo(bts, foh->obj_class, &foh->obj_inst); obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst); if (!mo || !obj) - return oml_fom_ack_nack(msg, NM_NACK_OBJINST_UNKN); + return oml_send_msg(oml_fom_ack_nack(msg, + NM_NACK_OBJINST_UNKN)); /* Step 2: Do some global dependency/consistency checking */ if (mo->nm_state.administrative == adm_state) @@ -800,7 +823,7 @@ static int down_fom(struct gsm_bts *bts, struct msgb *msg) if (foh->obj_inst.bts_nr != 0 && foh->obj_inst.bts_nr != 0xff) { LOGP(DOML, LOGL_INFO, "Formatted O&M with BTS %d out of range.\n", foh->obj_inst.bts_nr); - return oml_fom_ack_nack(msg, NM_NACK_BTSNR_UNKN); + return oml_send_msg(oml_fom_ack_nack(msg, NM_NACK_BTSNR_UNKN)); } switch (foh->msg_type) { @@ -810,15 +833,18 @@ static int down_fom(struct gsm_bts *bts, struct msgb *msg) case NM_MT_SET_RADIO_ATTR: trx = gsm_bts_trx_num(bts, foh->obj_inst.trx_nr); if (!trx) - return oml_fom_ack_nack(msg, NM_NACK_TRXNR_UNKN); + return oml_send_msg(oml_fom_ack_nack(msg, + NM_NACK_TRXNR_UNKN)); ret = oml_rx_set_radio_attr(trx, msg); break; case NM_MT_SET_CHAN_ATTR: trx = gsm_bts_trx_num(bts, foh->obj_inst.trx_nr); if (!trx) - return oml_fom_ack_nack(msg, NM_NACK_TRXNR_UNKN); + return oml_send_msg(oml_fom_ack_nack(msg, + NM_NACK_TRXNR_UNKN)); if (foh->obj_inst.ts_nr >= ARRAY_SIZE(trx->ts)) - return oml_fom_ack_nack(msg, NM_NACK_OBJINST_UNKN); + return oml_send_msg(oml_fom_ack_nack(msg, + NM_NACK_OBJINST_UNKN)); ret = oml_rx_set_chan_attr(&trx->ts[foh->obj_inst.ts_nr], msg); break; case NM_MT_OPSTART: @@ -833,7 +859,8 @@ static int down_fom(struct gsm_bts *bts, struct msgb *msg) default: LOGP(DOML, LOGL_INFO, "unknown Formatted O&M msg_type 0x%02x\n", foh->msg_type); - ret = oml_fom_ack_nack(msg, NM_NACK_MSGTYPE_INVAL); + ret = oml_send_msg(oml_fom_ack_nack(msg, + NM_NACK_MSGTYPE_INVAL)); } return ret; @@ -1000,17 +1027,19 @@ static int oml_ipa_set_attr(struct gsm_bts *bts, struct msgb *msg) rc = oml_tlv_parse(&tp, foh->data, msgb_l3len(msg) - sizeof(*foh)); if (rc < 0) - return oml_fom_ack_nack(msg, NM_NACK_INCORR_STRUCT); + return oml_send_msg(oml_fom_ack_nack(msg, + NM_NACK_INCORR_STRUCT)); /* Resolve MO by obj_class/obj_inst */ mo = gsm_objclass2mo(bts, foh->obj_class, &foh->obj_inst); obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst); if (!mo || !obj) - return oml_fom_ack_nack(msg, NM_NACK_OBJINST_UNKN); + return oml_send_msg(oml_fom_ack_nack(msg, + NM_NACK_OBJINST_UNKN)); rc = oml_ipa_mo_set_attr(bts, mo, obj, &tp); - return oml_fom_ack_nack(msg, rc); + return oml_send_msg(oml_fom_ack_nack(msg, rc)); } static int rx_oml_ipa_rsl_connect(struct gsm_bts_trx *trx, struct msgb *msg, @@ -1041,10 +1070,11 @@ static int rx_oml_ipa_rsl_connect(struct gsm_bts_trx *trx, struct msgb *msg, rc = e1inp_ipa_bts_rsl_connect(oml_link->ts->line, inet_ntoa(in), port); if (rc < 0) { LOGP(DOML, LOGL_ERROR, "Error in abis_open(RSL): %d\n", rc); - return oml_fom_ack_nack(msg, NM_NACK_CANT_PERFORM); + return oml_send_msg(oml_fom_ack_nack(msg, + NM_NACK_CANT_PERFORM)); } - return oml_fom_ack_nack(msg, 0); + return oml_send_msg(oml_fom_ack_nack(msg, 0)); } static int down_mom(struct gsm_bts *bts, struct msgb *msg) @@ -1071,13 +1101,13 @@ static int down_mom(struct gsm_bts *bts, struct msgb *msg) if (foh->obj_inst.bts_nr != 0 && foh->obj_inst.bts_nr != 0xff) { LOGP(DOML, LOGL_INFO, "Manufacturer O&M with BTS %d out of range.\n", foh->obj_inst.bts_nr); - return oml_fom_ack_nack(msg, NM_NACK_BTSNR_UNKN); + return oml_send_msg(oml_fom_ack_nack(msg, NM_NACK_BTSNR_UNKN)); } ret = oml_tlv_parse(&tp, foh->data, oh->length - sizeof(*foh)); if (ret < 0) { LOGP(DOML, LOGL_ERROR, "TLV parse error %d\n", ret); - return oml_fom_ack_nack(msg, NM_NACK_BTSNR_UNKN); + return oml_send_msg(oml_fom_ack_nack(msg, NM_NACK_BTSNR_UNKN)); } abis_nm_debugp_foh(DOML, foh); @@ -1094,7 +1124,8 @@ static int down_mom(struct gsm_bts *bts, struct msgb *msg) default: LOGP(DOML, LOGL_INFO, "Manufacturer Formatted O&M msg_type 0x%02x\n", foh->msg_type); - ret = oml_fom_ack_nack(msg, NM_NACK_MSGTYPE_INVAL); + ret = oml_send_msg(oml_fom_ack_nack(msg, + NM_NACK_MSGTYPE_INVAL)); } return ret; diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c index 4ebf664..a268294 100644 --- a/src/osmo-bts-sysmo/oml.c +++ b/src/osmo-bts-sysmo/oml.c @@ -1548,7 +1548,7 @@ int bts_model_apply_oml(struct gsm_bts *bts, struct msgb *msg, } /* FIXME: we actaully need to send a ACK or NACK for the OML message */ - return oml_fom_ack_nack(msg, 0); + return oml_send_msg(oml_fom_ack_nack(msg, 0)); } /* callback from OML */ -- 1.7.10.4 From dwillmann at sysmocom.de Wed May 21 13:08:18 2014 From: dwillmann at sysmocom.de (Daniel Willmann) Date: Wed, 21 May 2014 15:08:18 +0200 Subject: [PATCH 1/2] write_queue: Avoid possible use-after-free if fd is read-/writable Message-ID: If the FD is both readable and writable and the read callback closes the connection (and frees the surrounding structure) we shouldn't call the write callback (or check anything else in the read fd). With this patch callback functions can return -EBADFD if they don't want the FD to be handled any more. --- src/write_queue.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/write_queue.c b/src/write_queue.c index cef40f8..d17493d 100644 --- a/src/write_queue.c +++ b/src/write_queue.c @@ -21,8 +21,15 @@ * */ +#include #include +#define HANDLE_BAD_FD(rc, label) \ + do { \ + if (rc == -EBADFD) \ + goto label; \ + } while (0); + /*! \addtogroup write_queue * @{ */ @@ -39,14 +46,19 @@ int osmo_wqueue_bfd_cb(struct osmo_fd *fd, unsigned int what) { struct osmo_wqueue *queue; + int rc; queue = container_of(fd, struct osmo_wqueue, bfd); - if (what & BSC_FD_READ) - queue->read_cb(fd); + if (what & BSC_FD_READ) { + rc = queue->read_cb(fd); + HANDLE_BAD_FD(rc, err_badfd); + } - if (what & BSC_FD_EXCEPT) - queue->except_cb(fd); + if (what & BSC_FD_EXCEPT) { + rc = queue->except_cb(fd); + HANDLE_BAD_FD(rc, err_badfd); + } if (what & BSC_FD_WRITE) { struct msgb *msg; @@ -58,16 +70,21 @@ int osmo_wqueue_bfd_cb(struct osmo_fd *fd, unsigned int what) --queue->current_length; msg = msgb_dequeue(&queue->msg_queue); - queue->write_cb(fd, msg); + rc = queue->write_cb(fd, msg); msgb_free(msg); + HANDLE_BAD_FD(rc, err_badfd); + if (!llist_empty(&queue->msg_queue)) fd->when |= BSC_FD_WRITE; } } return 0; +err_badfd: + return rc; } +#undef HANDLE_BAD_FD /*! \brief Initialize a \ref osmo_wqueue structure * \param[in] queue Write queue to operate on -- 1.8.4.2 From dwillmann at sysmocom.de Wed May 21 13:08:19 2014 From: dwillmann at sysmocom.de (Daniel Willmann) Date: Wed, 21 May 2014 15:08:19 +0200 Subject: [PATCH 2/2] vty: Avoid use-after-free in VTY telnet interface In-Reply-To: References: Message-ID: If the read callback closes the connection conn is already freed so we can't derefernce it. Instead return -EBADFD in the read function if it closed the connection and check for that. --- src/vty/telnet_interface.c | 3 +-- src/vty/vty.c | 5 +++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vty/telnet_interface.c b/src/vty/telnet_interface.c index 32ab6be..0a04d15 100644 --- a/src/vty/telnet_interface.c +++ b/src/vty/telnet_interface.c @@ -120,7 +120,7 @@ static int client_data(struct osmo_fd *fd, unsigned int what) } /* vty might have been closed from vithin vty_read() */ - if (!conn->vty) + if (rc == -EBADFD) return rc; if (what & BSC_FD_WRITE) { @@ -193,7 +193,6 @@ void vty_event(enum event event, int sock, struct vty *vty) break; case VTY_CLOSED: /* vty layer is about to free() vty */ - connection->vty = NULL; telnet_close_client(bfd); break; default: diff --git a/src/vty/vty.c b/src/vty/vty.c index 8bfc35c..fc86bdf 100644 --- a/src/vty/vty.c +++ b/src/vty/vty.c @@ -1432,9 +1432,10 @@ int vty_read(struct vty *vty) } /* Check status. */ - if (vty->status == VTY_CLOSE) + if (vty->status == VTY_CLOSE) { vty_close(vty); - else { + return -EBADFD; + } else { vty_event(VTY_WRITE, vty_sock, vty); vty_event(VTY_READ, vty_sock, vty); } -- 1.8.4.2 From dwillmann at sysmocom.de Wed May 21 13:46:43 2014 From: dwillmann at sysmocom.de (Daniel Willmann) Date: Wed, 21 May 2014 15:46:43 +0200 Subject: [openbsc 1/2] rtp_proxy: Prevent out-of-bounds read in rtcp_sdes_cname_mangle Message-ID: <8c86d1c494e52a507b63eda0f42fbc9288a9d27c.1400680004.git.daniel@totalueberwachung.de> In rtcp_sdes_cname_mangle when skipping over additional zeroes at the end of a chunk we should not read past the actual message (rtcp_end). Fixes CID #1206579 --- openbsc/src/libtrau/rtp_proxy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/libtrau/rtp_proxy.c b/openbsc/src/libtrau/rtp_proxy.c index 122daf2..1567323 100644 --- a/openbsc/src/libtrau/rtp_proxy.c +++ b/openbsc/src/libtrau/rtp_proxy.c @@ -374,7 +374,7 @@ static int rtcp_sdes_cname_mangle(struct msgb *msg, struct rtcp_hdr *rh, tag = *cur++; if (tag == 0) { /* end of chunk, skip additional zero */ - while (*cur++ == 0) { } + while ((*cur++ == 0) && (cur < rtcp_end)) { } break; } len = *cur++; -- 1.8.4.2 From dwillmann at sysmocom.de Wed May 21 13:46:44 2014 From: dwillmann at sysmocom.de (Daniel Willmann) Date: Wed, 21 May 2014 15:46:44 +0200 Subject: [openbsc 2/2] bsc_hack: Don't strdup the string arguments In-Reply-To: <8c86d1c494e52a507b63eda0f42fbc9288a9d27c.1400680004.git.daniel@totalueberwachung.de> References: <8c86d1c494e52a507b63eda0f42fbc9288a9d27c.1400680004.git.daniel@totalueberwachung.de> Message-ID: <7b79641675cdb5b6f782de1d8649f332d5c13084.1400680004.git.daniel@totalueberwachung.de> Fixes CIDs #1206577, #1206578 --- openbsc/src/osmo-nitb/bsc_hack.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openbsc/src/osmo-nitb/bsc_hack.c b/openbsc/src/osmo-nitb/bsc_hack.c index 61141fd..3307bc6 100644 --- a/openbsc/src/osmo-nitb/bsc_hack.c +++ b/openbsc/src/osmo-nitb/bsc_hack.c @@ -148,10 +148,10 @@ static void handle_options(int argc, char **argv) daemonize = 1; break; case 'l': - database_name = strdup(optarg); + database_name = optarg; break; case 'c': - config_file = strdup(optarg); + config_file = optarg; break; case 'p': create_pcap_file(optarg); -- 1.8.4.2 From holger at freyther.de Fri May 23 06:45:45 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Fri, 23 May 2014 08:45:45 +0200 Subject: [PATCH] timer: Use the now parameter when it is not NULL Message-ID: <1400827545-23161-1-git-send-email-holger@freyther.de> From: Holger Hans Peter Freyther The code would have used an uninitialized current_time in case "now" was not NULL. As now is const and timersub expects a non const parameter I decided to copy now into current_time. Fixes: CID #1040661 --- src/timer.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/timer.c b/src/timer.c index 5988aef..c8376c8 100644 --- a/src/timer.c +++ b/src/timer.c @@ -141,10 +141,10 @@ int osmo_timer_remaining(const struct osmo_timer_list *timer, { struct timeval current_time; - if (!now) { + if (!now) gettimeofday(¤t_time, NULL); - now = ¤t_time; - } + else + current_time = *now; timersub(&timer->timeout, ¤t_time, remaining); -- 1.9.1 From holger at freyther.de Fri May 23 06:54:57 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Fri, 23 May 2014 08:54:57 +0200 Subject: [PATCH 1/2] gsm0411_smr: Make the look-up table static Message-ID: <1400828098-24079-1-git-send-email-holger@freyther.de> From: Holger Hans Peter Freyther --- src/gsm/gsm0411_smr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gsm/gsm0411_smr.c b/src/gsm/gsm0411_smr.c index b243c86..a7e9d24 100644 --- a/src/gsm/gsm0411_smr.c +++ b/src/gsm/gsm0411_smr.c @@ -94,7 +94,7 @@ void gsm411_smr_clear(struct gsm411_smr_inst *inst) osmo_timer_del(&inst->rp_timer); } -const char *smr_state_names[] = { +static const char *smr_state_names[] = { "IDLE", "WAIT_FOR_RP_ACK", "illegal state 2" -- 1.9.1 From holger at freyther.de Fri May 23 06:54:58 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Fri, 23 May 2014 08:54:58 +0200 Subject: [PATCH 2/2] gsm0411_smr: Fix the size of the array In-Reply-To: <1400828098-24079-1-git-send-email-holger@freyther.de> References: <1400828098-24079-1-git-send-email-holger@freyther.de> Message-ID: <1400828098-24079-2-git-send-email-holger@freyther.de> From: Holger Hans Peter Freyther The code is lacking a "," at the end of a string and we ended up doing string concatination instead of having an invalid state. Fixes Coverity CID 1206564 --- src/gsm/gsm0411_smr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gsm/gsm0411_smr.c b/src/gsm/gsm0411_smr.c index a7e9d24..eb1f036 100644 --- a/src/gsm/gsm0411_smr.c +++ b/src/gsm/gsm0411_smr.c @@ -97,7 +97,7 @@ void gsm411_smr_clear(struct gsm411_smr_inst *inst) static const char *smr_state_names[] = { "IDLE", "WAIT_FOR_RP_ACK", - "illegal state 2" + "illegal state 2", "WAIT_TO_TX_RP_ACK", "WAIT_FOR_RETRANS_T", }; -- 1.9.1 From admin at manateeshome.com Sun May 25 07:01:56 2014 From: admin at manateeshome.com (Pierre Kim) Date: Sun, 25 May 2014 16:01:56 +0900 Subject: GPRS broken in master Message-ID: <587b01cf77e7$38b747c0$aa25d740$@manateeshome.com> Hello, I updated my OpenBSC repo today and found that the GPRS is not working properly with the newest osmo-nitb. I tried several different versions of osmo-nitb and osmo-sgsn to localize the problem and concluded that osmo-nitb is causing the issue. The phone can attach to GPRS and PDP context request is accepted, but the phone still cannot send or receive data. <000f> sgsn_libgtp.c:126 Create PDP Context <000f> sgsn_libgtp.c:379 libgtp cb_conf(type=16, cause=128, pdp=0xb733cea0, cbp=0x8839230) <000f> sgsn_libgtp.c:265 Received CREATE PDP CTX CONF, cause=128(Request accepted) <0013> gprs_sndcp.c:297 SNSM-ACTIVATE.ind (lle=0x8838568 TLLI=d527d1cf, SAPI=3, NSAPI=5) <0011> gprs_bssgp.c:503 BSSGP BVCI=0 TLLI=d527d1cf Rx LLC DISCARDED <0011> gprs_bssgp.c:376 BSSGP TLLI=0xd527d1cf Rx UPLINK-UNITDATA <0012> gprs_llc.c:551 LLC SAPI=1 C FCS=0xd9c320CMD=UI DATA <0011> gprs_bssgp.c:503 BSSGP BVCI=0 TLLI=d527d1cf Rx LLC DISCARDED <0011> gprs_bssgp.c:376 BSSGP TLLI=0xd527d1cf Rx UPLINK-UNITDATA <0012> gprs_llc.c:551 LLC SAPI=1 C FCS=0x26346bCMD=UI DATA <0011> gprs_bssgp.c:503 BSSGP BVCI=0 TLLI=d527d1cf Rx LLC DISCARDED <0011> gprs_bssgp.c:376 BSSGP TLLI=0xd527d1cf Rx UPLINK-UNITDATA <0012> gprs_llc.c:551 LLC SAPI=1 C FCS=0x4a642eCMD=UI DATA Please let me know if you need more logs or packet dump. I will be reverting to older revisions to find out when exactly it got broken Regards, Pierre -------------- next part -------------- An HTML attachment was scrubbed... URL: From holger at freyther.de Sun May 25 10:04:59 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Sun, 25 May 2014 12:04:59 +0200 Subject: GPRS broken in master In-Reply-To: <587b01cf77e7$38b747c0$aa25d740$@manateeshome.com> References: <587b01cf77e7$38b747c0$aa25d740$@manateeshome.com> Message-ID: <20140525100459.GB27873@xiaoyu.lan> On Sun, May 25, 2014 at 04:01:56PM +0900, Pierre Kim wrote: > Hello, Good Morning, > I updated my OpenBSC repo today and found that the GPRS is not working > properly with the newest osmo-nitb. from which version to which did you update? Why do you think it is osmo-nitb and not the SGSN? In general the more precise you are the more easy it is to help you. > I tried several different versions of osmo-nitb and osmo-sgsn to localize > the problem and concluded that osmo-nitb is causing the issue. > I will be reverting to older revisions to find out when exactly it got > broken If you use git bisect you can help us to point to a version. > <0011> gprs_bssgp.c:503 BSSGP BVCI=0 TLLI=d527d1cf Rx LLC DISCARDED Have you started to look into _why_ it is being discarded? This message is sent by the PCU and means that data could not be delivered from the PCU to the MobileStation within the specified timeout. How can that be? holger From holger at freyther.de Mon May 26 06:22:36 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Mon, 26 May 2014 08:22:36 +0200 Subject: [PATCH 1/3] lchan: Speculative "fix" for error and late reply Message-ID: <1401085358-3975-1-git-send-email-holger@freyther.de> From: Holger Hans Peter Freyther Looking at the code it seemed possible that a channel would transition from BROKEN to NONE. Or worse from NONE to BROKEN. Start the timer _after_ the channel has been released. --- openbsc/src/libbsc/abis_rsl.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index 5d40794..984fa7e 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -52,6 +52,7 @@ enum sacch_deact { }; static int rsl_send_imm_assignment(struct gsm_lchan *lchan); +static void error_timeout_cb(void *data); static void send_lchan_signal(int sig_no, struct gsm_lchan *lchan, struct gsm_meas_rep *resp) @@ -64,9 +65,15 @@ static void send_lchan_signal(int sig_no, struct gsm_lchan *lchan, static void do_lchan_free(struct gsm_lchan *lchan) { - /* we have an error timer pending to release that */ - if (lchan->state != LCHAN_S_REL_ERR) + /* We start the error timer to make the channel available again */ + if (lchan->state == LCHAN_S_REL_ERR) { + lchan->error_timer.data = lchan; + lchan->error_timer.cb = error_timeout_cb; + osmo_timer_schedule(&lchan->error_timer, + lchan->ts->trx->bts->network->T3111 + 2, 0); + } else { rsl_lchan_set_state(lchan, LCHAN_S_NONE); + } lchan_free(lchan); } @@ -679,8 +686,6 @@ static int rsl_rf_chan_release(struct gsm_lchan *lchan, int error, DEBUGP(DRSL, "%s RF Channel Release CMD due error %d\n", gsm_lchan_name(lchan), error); if (error) { - struct e1inp_sign_link *sign_link = msg->dst; - /* * FIXME: GSM 04.08 gives us two options for the abnormal * chanel release. This can be either like in the non-existent @@ -708,10 +713,6 @@ static int rsl_rf_chan_release(struct gsm_lchan *lchan, int error, * TODO: start T3109 now. */ rsl_lchan_set_state(lchan, LCHAN_S_REL_ERR); - lchan->error_timer.data = lchan; - lchan->error_timer.cb = error_timeout_cb; - osmo_timer_schedule(&lchan->error_timer, - sign_link->trx->bts->network->T3111 + 2, 0); } /* Start another timer or assume the BTS sends a ACK/NACK? */ -- 1.9.1 From holger at freyther.de Mon May 26 06:22:37 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Mon, 26 May 2014 08:22:37 +0200 Subject: [PATCH 2/3] rsl: Avoid double channel release procedure in error conditions In-Reply-To: <1401085358-3975-1-git-send-email-holger@freyther.de> References: <1401085358-3975-1-git-send-email-holger@freyther.de> Message-ID: <1401085358-3975-2-git-send-email-holger@freyther.de> From: Holger Hans Peter Freyther When we receive an ERROR INDICATION and CONNECTION FAILURE we might call rsl_rf_chan_release multiple times. The channel release handling is still a bit messy and there too many paths that lead to the call. 1.) In case we receive an ERROR INDICATION for SAPI=3. A RLL error signal will be emitted that leads to the release of the channel through the SMS code in case of the NITB. The call to rsl_rf_chan_release might be a double release. 2.) In case a CONNECTION FAILURE is received when the release process has already been started we would unconditionally call rsl_rf_chan_release as well. Because the lchan state is changed by the callers of the rsl_rf_chan_release we can not move the state checking into this code but need to do it in the caller. The issue was seen in a trace from Rhizomatica and I created the DoubleRelease.st to re-produce the issue and verified that we have no duplicate RF Channel Releses. The other option would be to introduce a new state to track the release process and see if we have already released SAPIs deactivated the SACCH or such. We can not simply look at these as for a channel that fails to activate they will be null already. --- openbsc/src/libbsc/abis_rsl.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index 984fa7e..de76d0f 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -1013,9 +1013,15 @@ static int rsl_rx_conn_fail(struct msgb *msg) struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); struct tlv_parsed tp; - /* FIXME: print which channel */ - LOGP(DRSL, LOGL_NOTICE, "%s CONNECTION FAIL: RELEASING ", - gsm_lchan_name(msg->lchan)); + LOGP(DRSL, LOGL_NOTICE, "%s CONNECTION FAIL: RELEASING state %s ", + gsm_lchan_name(msg->lchan), + gsm_lchans_name(msg->lchan->state)); + + /* We might have already received an ERROR INDICATION */ + if (msg->lchan->state != LCHAN_S_ACTIVE) { + LOGPC(DRSL, LOGL_NOTICE, "\n"); + return 0; + } rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); @@ -1587,12 +1593,21 @@ static int rsl_rx_rll_err_ind(struct msgb *msg) } rlm_cause = *TLVP_VAL(&tp, RSL_IE_RLM_CAUSE); - LOGP(DRLL, LOGL_ERROR, "%s ERROR INDICATION cause=%s\n", + LOGP(DRLL, LOGL_ERROR, "%s ERROR INDICATION cause=%s in state=%s\n", gsm_lchan_name(msg->lchan), - rsl_rlm_cause_name(rlm_cause)); + rsl_rlm_cause_name(rlm_cause), + gsm_lchans_name(msg->lchan->state)); + + /* If the channel is already failing no need to inform anyone. */ + if (msg->lchan->state != LCHAN_S_ACTIVE) + return 0; rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_ERR_IND); + /* The channel might have been released already. */ + if (msg->lchan->state != LCHAN_S_ACTIVE) + return 0; + if (rlm_cause == RLL_CAUSE_T200_EXPIRED) { osmo_counter_inc(msg->lchan->ts->trx->bts->network->stats.chan.rll_err); return rsl_rf_chan_release(msg->lchan, 1, SACCH_DEACTIVATE); -- 1.9.1 From holger at freyther.de Mon May 26 06:22:38 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Mon, 26 May 2014 08:22:38 +0200 Subject: [PATCH 3/3] rsl: Check if the channel is active and then start the channel release In-Reply-To: <1401085358-3975-1-git-send-email-holger@freyther.de> References: <1401085358-3975-1-git-send-email-holger@freyther.de> Message-ID: <1401085358-3975-3-git-send-email-holger@freyther.de> From: Holger Hans Peter Freyther In case we receive ERROR INDICATION and CONNECTION FAILURE we only want to RF Channel Release the lchan once. This code is more simple and should work as reliable as the previous commit. --- openbsc/src/libbsc/abis_rsl.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index de76d0f..748ab7e 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -726,6 +726,16 @@ static int rsl_rf_chan_release(struct gsm_lchan *lchan, int error, return rc; } +/* + * Special handling for channel releases in the error case. + */ +static int rsl_rf_chan_release_err(struct gsm_lchan *lchan) +{ + if (lchan->state != LCHAN_S_ACTIVE) + return 0; + return rsl_rf_chan_release(lchan, 1, SACCH_DEACTIVATE); +} + static int rsl_rx_rf_chan_rel_ack(struct gsm_lchan *lchan) { @@ -1017,12 +1027,6 @@ static int rsl_rx_conn_fail(struct msgb *msg) gsm_lchan_name(msg->lchan), gsm_lchans_name(msg->lchan->state)); - /* We might have already received an ERROR INDICATION */ - if (msg->lchan->state != LCHAN_S_ACTIVE) { - LOGPC(DRSL, LOGL_NOTICE, "\n"); - return 0; - } - rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); if (TLVP_PRESENT(&tp, RSL_IE_CAUSE)) @@ -1031,7 +1035,7 @@ static int rsl_rx_conn_fail(struct msgb *msg) LOGPC(DRSL, LOGL_NOTICE, "\n"); osmo_counter_inc(msg->lchan->ts->trx->bts->network->stats.chan.rf_fail); - return rsl_rf_chan_release(msg->lchan, 1, SACCH_DEACTIVATE); + return rsl_rf_chan_release_err(msg->lchan); } static void print_meas_rep_uni(struct gsm_meas_rep_unidir *mru, @@ -1598,19 +1602,11 @@ static int rsl_rx_rll_err_ind(struct msgb *msg) rsl_rlm_cause_name(rlm_cause), gsm_lchans_name(msg->lchan->state)); - /* If the channel is already failing no need to inform anyone. */ - if (msg->lchan->state != LCHAN_S_ACTIVE) - return 0; - rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_ERR_IND); - /* The channel might have been released already. */ - if (msg->lchan->state != LCHAN_S_ACTIVE) - return 0; - if (rlm_cause == RLL_CAUSE_T200_EXPIRED) { osmo_counter_inc(msg->lchan->ts->trx->bts->network->stats.chan.rll_err); - return rsl_rf_chan_release(msg->lchan, 1, SACCH_DEACTIVATE); + return rsl_rf_chan_release_err(msg->lchan); } return 0; -- 1.9.1 From holger at freyther.de Wed May 28 14:58:11 2014 From: holger at freyther.de (Holger Hans Peter Freyther) Date: Wed, 28 May 2014 16:58:11 +0200 Subject: trau_decode_fr memory corruption. Fix requested Message-ID: <20140528145811.GA6793@xiaoyu.lan> Dear Andreas, Harald, I don't really know much about the bit order of TRAU frames but the trau_test.c is causing an out of bounds access to the gsm_fr_map. Re-produce (GCC >= 3.8 or clang >= 3.2 required): $ make clean && make CFLAGS+="-ggdb3 -Og -fsanitize=address" $ cd tests/trau $ ./trau_test Issue: Breakpoint 1, 0xb69e7810 in __asan_report_error () from /usr/lib/i386-linux-gnu/libasan.so.0 (gdb) bt #0 0xb69e7810 in __asan_report_error () from /usr/lib/i386-linux-gnu/libasan.so.0 #1 0xb69e08cf in __asan_report_load1 () from /usr/lib/i386-linux-gnu/libasan.so.0 #2 0x0804c4e7 in trau_encode_fr (tf=tf at entry=0xbffff530, data=data at entry=0xbffff700 ) at trau_mux.c:441 #3 0x08048e06 in test_trau_fr_efr (data=, data at entry=0xbffff700 ) at trau_test.c:35 #4 0x080494bf in main () at trau_test.c:70 (gdb) frame2 Undefined command: "frame2". Try "help". (gdb) frame 2 #2 0x0804c4e7 in trau_encode_fr (tf=tf at entry=0xbffff530, data=data at entry=0xbffff700 ) at trau_mux.c:441 441 k = gsm_fr_map[++l]-1; (gdb) p l $1 = 76 (gdb) p l $2 = 76 (gdb) p sizeof(gsm_fr_map) $3 = 76 Please fix as soon as possible as I would like to enable ASAN checking on the jenkins as soon as possible. kind regards holger From dwillmann at sysmocom.de Fri May 30 15:57:58 2014 From: dwillmann at sysmocom.de (Daniel Willmann) Date: Fri, 30 May 2014 17:57:58 +0200 Subject: osmo-pcu: Upgrade DL tbf to use multislot if possible Message-ID: <1401465481-28566-1-git-send-email-dwillmann@sysmocom.de> Hello, if the network iniates a data transfer it will page the MS to open a TBF and since this paging happens over the CCCH it can only ask the MS to use one PDCH initially. With this patch (and if there are more PDCH ts available) the PCU will remember that it can upgrade to use multiple timeslots and send a downlink assignment with the new timeslot allocation over the TBF. Regards, Daniel -- - Daniel Willmann http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Schivelbeiner Str. 5 * 10439 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte From dwillmann at sysmocom.de Fri May 30 15:57:59 2014 From: dwillmann at sysmocom.de (Daniel Willmann) Date: Fri, 30 May 2014 17:57:59 +0200 Subject: [osmo-pcu 1/3] tbf/bts: Rename tbf->snd_dl_ack to tbf->rcvd_dl_ack In-Reply-To: <1401465481-28566-1-git-send-email-dwillmann@sysmocom.de> References: <1401465481-28566-1-git-send-email-dwillmann@sysmocom.de> Message-ID: <8d1337120f7cc17da78c0a0496e6d02a94907a38.1401463598.git.daniel@totalueberwachung.de> This function is called to act upon a received DL ACK packet so this name makes more sense. --- src/bts.cpp | 2 +- src/tbf.cpp | 2 +- src/tbf.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bts.cpp b/src/bts.cpp index ff16e29..6c02408 100644 --- a/src/bts.cpp +++ b/src/bts.cpp @@ -805,7 +805,7 @@ void gprs_rlcmac_pdch::rcv_control_dl_ack_nack(Packet_Downlink_Ack_Nack_t *ack_n LOGP(DRLCMAC, LOGL_DEBUG, "RX: [PCU <- BTS] %s Packet Downlink Ack/Nack\n", tbf_name(tbf)); tbf->poll_state = GPRS_RLCMAC_POLL_NONE; - rc = tbf->snd_dl_ack( + rc = tbf->rcvd_dl_ack( ack_nack->Ack_Nack_Description.FINAL_ACK_INDICATION, ack_nack->Ack_Nack_Description.STARTING_SEQUENCE_NUMBER, ack_nack->Ack_Nack_Description.RECEIVED_BLOCK_BITMAP); diff --git a/src/tbf.cpp b/src/tbf.cpp index d6b3802..b20d0fc 100644 --- a/src/tbf.cpp +++ b/src/tbf.cpp @@ -1425,7 +1425,7 @@ int gprs_rlcmac_tbf::maybe_start_new_window() return 0; } -int gprs_rlcmac_tbf::snd_dl_ack(uint8_t final_ack, uint8_t ssn, uint8_t *rbb) +int gprs_rlcmac_tbf::rcvd_dl_ack(uint8_t final_ack, uint8_t ssn, uint8_t *rbb) { LOGP(DRLCMACDL, LOGL_DEBUG, "%s downlink acknowledge\n", tbf_name(this)); diff --git a/src/tbf.h b/src/tbf.h index c301960..24b98d2 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -103,7 +103,7 @@ struct gprs_rlcmac_tbf { struct msgb *create_dl_ass(uint32_t fn); struct msgb *create_ul_ass(uint32_t fn); struct msgb *create_ul_ack(uint32_t fn); - int snd_dl_ack(uint8_t final, uint8_t ssn, uint8_t *rbb); + int rcvd_dl_ack(uint8_t final, uint8_t ssn, uint8_t *rbb); int snd_ul_ud(); /* blocks were acked */ -- 1.8.4.2 From dwillmann at sysmocom.de Fri May 30 15:58:00 2014 From: dwillmann at sysmocom.de (Daniel Willmann) Date: Fri, 30 May 2014 17:58:00 +0200 Subject: [osmo-pcu 2/3] tbf/bts, encoding: Keep track of WAIT_RELEASE state for DL assignment In-Reply-To: <1401465481-28566-1-git-send-email-dwillmann@sysmocom.de> References: <1401465481-28566-1-git-send-email-dwillmann@sysmocom.de> Message-ID: <6d3652933ae687a8d1a452073d3e7f4e618485b8.1401463598.git.daniel@totalueberwachung.de> The current code does not properly distinguish between DL assignments to reuse a tbf (after it was put in state WAIT_RELEASE) and DL assignments for an active tbf to change the allocation of the PDCH timeslots. This patch introduces a new variable was_releasing which remembers if trigger_dl_ass() was called with a tbf in state WAIT_RELEASE. In that case we have to set the CONTROL_ACK field in the download assignment. This should allow us to send DL assignments to change PDCH TS allocation of a tbf before we enter FLOW state. --- src/bts.cpp | 2 ++ src/encoding.cpp | 2 +- src/tbf.cpp | 3 ++- src/tbf.h | 4 ++++ 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/bts.cpp b/src/bts.cpp index 6c02408..9003099 100644 --- a/src/bts.cpp +++ b/src/bts.cpp @@ -474,6 +474,7 @@ void BTS::trigger_dl_ass( old_tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_SEND_ASS; /* use TA from old TBF */ tbf->ta = old_tbf->ta; + tbf->was_releasing = tbf->state_is(GPRS_RLCMAC_WAIT_RELEASE); /* change state */ tbf_new_state(tbf, GPRS_RLCMAC_ASSIGN); tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_PACCH); @@ -485,6 +486,7 @@ void BTS::trigger_dl_ass( LOGP(DRLCMAC, LOGL_ERROR, "No valid IMSI!\n"); return; } + tbf->was_releasing = tbf->state_is(GPRS_RLCMAC_WAIT_RELEASE); /* change state */ tbf_new_state(tbf, GPRS_RLCMAC_ASSIGN); tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_CCCH); diff --git a/src/encoding.cpp b/src/encoding.cpp index 51b0fbe..13848aa 100644 --- a/src/encoding.cpp +++ b/src/encoding.cpp @@ -267,7 +267,7 @@ void Encoding::write_packet_downlink_assignment(RlcMacDownlink_t * block, uint8_ block->u.Packet_Downlink_Assignment.MAC_MODE = 0x0; // Dynamic Allocation block->u.Packet_Downlink_Assignment.RLC_MODE = 0x0; // RLC acknowledged mode - block->u.Packet_Downlink_Assignment.CONTROL_ACK = old_downlink; // NW establishes no new DL TBF for the MS with running timer T3192 + block->u.Packet_Downlink_Assignment.CONTROL_ACK = tbf->was_releasing; // NW establishes no new DL TBF for the MS with running timer T3192 block->u.Packet_Downlink_Assignment.TIMESLOT_ALLOCATION = 0; // timeslot(s) for (tn = 0; tn < 8; tn++) { if (tbf->pdch[tn]) diff --git a/src/tbf.cpp b/src/tbf.cpp index b20d0fc..dd1f0fb 100644 --- a/src/tbf.cpp +++ b/src/tbf.cpp @@ -1405,6 +1405,8 @@ int gprs_rlcmac_tbf::maybe_start_new_window() /* report all outstanding packets as received */ gprs_rlcmac_received_lost(this, received, 0); + tbf_new_state(this, GPRS_RLCMAC_WAIT_RELEASE); + /* check for LLC PDU in the LLC Queue */ msg = llc_dequeue(gprs_bssgp_pcu_current_bctx()); if (!msg) { @@ -1414,7 +1416,6 @@ int gprs_rlcmac_tbf::maybe_start_new_window() tbf_timer_start(this, 3193, bts_data()->t3193_msec / 1000, (bts_data()->t3193_msec % 1000) * 1000); - tbf_new_state(this, GPRS_RLCMAC_WAIT_RELEASE); return 0; } diff --git a/src/tbf.h b/src/tbf.h index 24b98d2..0ee9718 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -217,6 +217,10 @@ struct gprs_rlcmac_tbf { * stops to iterate over all tbf in its current form */ enum gprs_rlcmac_tbf_state state; + /* Remember if the tbf was in wait_release state when we want to + * schedule a new dl assignment */ + uint8_t was_releasing; + /* store the BTS this TBF belongs to */ BTS *bts; -- 1.8.4.2 From dwillmann at sysmocom.de Fri May 30 15:58:01 2014 From: dwillmann at sysmocom.de (Daniel Willmann) Date: Fri, 30 May 2014 17:58:01 +0200 Subject: [osmo-pcu 3/3] tbf: Re-send dl assignment if we can upgrade to multislot In-Reply-To: <1401465481-28566-1-git-send-email-dwillmann@sysmocom.de> References: <1401465481-28566-1-git-send-email-dwillmann@sysmocom.de> Message-ID: The current code would only ever assign one PDCH for the initial assignment (from CCCH). Only if reuse_tbf is called the algorithm would actually use multiple DL PDCHs if possible. This patch introduced a tbf attribute upgrade_to_multislot that is set if we have multiple PDCH configured, and support multislot assignment, but can only assign a single PDCH (alloc_algorithm_b, parameter single is set). In this case after the assignment completes (and the MS is listening on a PDCH) we resend a DL assignment though the PACCH and this time we can assign multiple timeslots. --- src/gprs_rlcmac_ts_alloc.cpp | 9 +++++++++ src/tbf.cpp | 22 ++++++++++++++++++++-- src/tbf.h | 3 +++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/gprs_rlcmac_ts_alloc.cpp b/src/gprs_rlcmac_ts_alloc.cpp index 366732c..a97cc65 100644 --- a/src/gprs_rlcmac_ts_alloc.cpp +++ b/src/gprs_rlcmac_ts_alloc.cpp @@ -175,6 +175,8 @@ int alloc_algorithm_a(struct gprs_rlcmac_bts *bts, /* the only one TS is the common TS */ tbf->first_ts = tbf->first_common_ts = ts; + tbf->upgrade_to_multislot = 0; + return 0; } @@ -665,10 +667,17 @@ int alloc_algorithm_b(struct gprs_rlcmac_bts *bts, } } if (single && slotcount) { + uint8_t ts_count = 0; + for (ts = 0; ts < 8; ts++) + if ((tx_window & (1 << ts))) + ts_count++; + + tbf->upgrade_to_multislot = (ts_count > 1); LOGP(DRLCMAC, LOGL_INFO, "Using single slot at TS %d for %s\n", tbf->first_ts, (tbf->direction == GPRS_RLCMAC_DL_TBF) ? "DL" : "UL"); } else { + tbf->upgrade_to_multislot = 0; LOGP(DRLCMAC, LOGL_INFO, "Using %d slots for %s\n", slotcount, (tbf->direction == GPRS_RLCMAC_DL_TBF) ? "DL" : "UL"); } diff --git a/src/tbf.cpp b/src/tbf.cpp index dd1f0fb..3a2ad73 100644 --- a/src/tbf.cpp +++ b/src/tbf.cpp @@ -574,11 +574,29 @@ void gprs_rlcmac_tbf::handle_timeout() "in assign state\n", tbf_name(this)); } if ((state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH))) { - /* change state to FLOW, so scheduler will start transmission */ dir.dl.wait_confirm = 0; if (state_is(GPRS_RLCMAC_ASSIGN)) { - tbf_new_state(this, GPRS_RLCMAC_FLOW); tbf_assign_control_ts(this); + + if (!upgrade_to_multislot) { + /* change state to FLOW, so scheduler + * will start transmission */ + tbf_new_state(this, GPRS_RLCMAC_FLOW); + break; + } + + /* This tbf can be upgraded to use multiple DL + * timeslots and now that there is already one + * slot assigned send another DL assignment via + * PDCH. */ + + /* keep to flags */ + state_flags &= GPRS_RLCMAC_FLAG_TO_MASK; + state_flags &= ~(1 << GPRS_RLCMAC_FLAG_CCCH); + + update(); + + bts->trigger_dl_ass(this, this, NULL); } else LOGP(DRLCMAC, LOGL_NOTICE, "%s Continue flow after " "IMM.ASS confirm\n", tbf_name(this)); diff --git a/src/tbf.h b/src/tbf.h index 0ee9718..80e2068 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -221,6 +221,9 @@ struct gprs_rlcmac_tbf { * schedule a new dl assignment */ uint8_t was_releasing; + /* Can/should we upgrade this tbf to use multiple slots? */ + uint8_t upgrade_to_multislot; + /* store the BTS this TBF belongs to */ BTS *bts; -- 1.8.4.2