| #include <stdio.h> |
| #include <signal.h> |
| #include <osmocom/core/talloc.h> |
| #include <string.h> |
| #include <unistd.h> |
| #include <osmocom/abis/abis.h> |
| #include <osmocom/abis/e1_input.h> |
| #include <osmocom/core/logging.h> |
| #include <osmocom/core/application.h> |
| #include <osmocom/abis/ipaccess.h> |
| #include <osmocom/gsm/protocol/gsm_12_21.h> |
| #include <osmocom/gsm/ipa.h> |
| |
| static void *tall_test; |
| static struct e1inp_sign_link *oml_sign_link, *rsl_sign_link; |
| |
| #define DBTSTEST 0 |
| |
| struct log_info_cat bts_test_cat[] = { |
| [DBTSTEST] = { |
| .name = "DBTSTEST", |
| .description = "BTS-mode test", |
| .color = "\033[1;35m", |
| .enabled = 1, .loglevel = LOGL_NOTICE, |
| }, |
| }; |
| |
| const struct log_info bts_test_log_info = { |
| .filter_fn = NULL, |
| .cat = bts_test_cat, |
| .num_cat = ARRAY_SIZE(bts_test_cat), |
| }; |
| |
| enum bts_state_machine { |
| BTS_TEST_OML_SIGN_LINK_DOWN = 0, |
| BTS_TEST_OML_SIGN_LINK_UP, |
| BTS_TEST_OML_WAIT_SW_ACT_ACK, |
| }; |
| |
| static struct osmo_fd bts_eventfd; |
| static int eventfds[2]; |
| |
| static enum bts_state_machine bts_state = BTS_TEST_OML_SIGN_LINK_DOWN; |
| |
| static struct e1inp_sign_link * |
| sign_link_up(void *unit, struct e1inp_line *line, enum e1inp_sign_type type) |
| { |
| struct e1inp_sign_link *sign_link = NULL; |
| |
| switch(type) { |
| case E1INP_SIGN_OML: |
| LOGP(DBTSTEST, LOGL_NOTICE, "OML link up request received.\n"); |
| |
| e1inp_ts_config_sign(&line->ts[E1INP_SIGN_OML - 1], line); |
| sign_link = oml_sign_link = |
| e1inp_sign_link_create(&line->ts[E1INP_SIGN_OML - 1], |
| E1INP_SIGN_OML, NULL, 255, 0); |
| if (!oml_sign_link) { |
| LOGP(DBTSTEST, LOGL_ERROR, |
| "cannot create OML sign link\n"); |
| } |
| if (oml_sign_link) { |
| unsigned int event_type = 0; |
| |
| /* tell GSM 12.21 that we're ready via our eventfd. */ |
| if (write(eventfds[1], &event_type, |
| sizeof(unsigned int)) < 0) { |
| LOGP(DBTSTEST, LOGL_ERROR, "cannot write " |
| "event fd.\n"); |
| } |
| /* Now we can send OML messages to the BSC. */ |
| bts_state = BTS_TEST_OML_SIGN_LINK_UP; |
| } |
| e1inp_ipa_bts_rsl_connect_n(line, "127.0.0.1", IPA_TCP_PORT_RSL, 0); |
| break; |
| case E1INP_SIGN_RSL: |
| LOGP(DBTSTEST, LOGL_NOTICE, "RSL link up request received.\n"); |
| |
| e1inp_ts_config_sign(&line->ts[E1INP_SIGN_RSL - 1], line); |
| |
| sign_link = rsl_sign_link = |
| e1inp_sign_link_create(&line->ts[E1INP_SIGN_RSL - 1], |
| E1INP_SIGN_RSL, NULL, 0, 0); |
| if (!rsl_sign_link) { |
| LOGP(DBTSTEST, LOGL_ERROR, |
| "cannot create RSL sign link\n"); |
| } |
| break; |
| default: |
| return NULL; |
| } |
| if (sign_link) |
| LOGP(DBTSTEST, LOGL_NOTICE, "signal link has been set up.\n"); |
| |
| return sign_link; |
| } |
| |
| static void sign_link_down(struct e1inp_line *line) |
| { |
| LOGP(DBTSTEST, LOGL_NOTICE, "signal link has been closed\n"); |
| e1inp_sign_link_destroy(oml_sign_link); |
| e1inp_sign_link_destroy(rsl_sign_link); |
| } |
| |
| static int abis_nm_rcvmsg_fom(struct msgb *msg) |
| { |
| struct abis_om_fom_hdr *foh = msgb_l3(msg); |
| uint8_t mt = foh->msg_type; |
| int ret = 0; |
| |
| switch (mt) { |
| case NM_MT_SW_ACT_REQ_ACK: /* SW activate request ACK from BSC. */ |
| LOGP(DBTSTEST, LOGL_NOTICE, "Receive SW Act Req ACK\n"); |
| break; |
| default: |
| LOGP(DBTSTEST, LOGL_ERROR, "unknown OML message\n"); |
| break; |
| } |
| return ret; |
| } |
| |
| static int abis_nm_rcvmsg(struct msgb *msg) |
| { |
| int ret = 0; |
| struct abis_om_hdr *oh = msgb_l2(msg); |
| |
| msg->l3h = (unsigned char *)oh + sizeof(*oh); |
| switch (oh->mdisc) { |
| case ABIS_OM_MDISC_FOM: |
| ret = abis_nm_rcvmsg_fom(msg); |
| break; |
| default: |
| LOGP(DBTSTEST, LOGL_ERROR, "unknown OML message\n"); |
| break; |
| } |
| return ret; |
| } |
| |
| static int sign_link(struct msgb *msg) |
| { |
| int ret = 0; |
| struct e1inp_sign_link *link = msg->dst; |
| |
| switch(link->type) { |
| case E1INP_SIGN_OML: |
| LOGP(DBTSTEST, LOGL_NOTICE, "OML message received.\n"); |
| ret = abis_nm_rcvmsg(msg); |
| break; |
| case E1INP_SIGN_RSL: |
| LOGP(DBTSTEST, LOGL_NOTICE, "RSL message received.\n"); |
| break; |
| default: |
| LOGP(DBTSTEST, LOGL_ERROR, "Unknown signalling message.\n"); |
| break; |
| } |
| msgb_free(msg); |
| return ret; |
| } |
| |
| static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len) |
| { |
| oh->mdisc = ABIS_OM_MDISC_FOM; |
| oh->placement = ABIS_OM_PLACEMENT_ONLY; |
| oh->sequence = 0; |
| oh->length = len; |
| } |
| |
| static void fill_om_fom_hdr(struct abis_om_hdr *oh, uint8_t len, |
| uint8_t msg_type, uint8_t obj_class, |
| uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr) |
| { |
| struct abis_om_fom_hdr *foh = (struct abis_om_fom_hdr *) oh->data; |
| |
| fill_om_hdr(oh, len+sizeof(*foh)); |
| 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; |
| } |
| |
| #define OM_ALLOC_SIZE 1024 |
| #define OM_HEADROOM_SIZE 128 |
| |
| static struct msgb *nm_msgb_alloc(void) |
| { |
| return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE, "BTS/test"); |
| } |
| |
| static int abis_nm_sw_act_req(struct e1inp_sign_link *sign_link, |
| uint8_t obj_class, |
| uint8_t i1, uint8_t i2, uint8_t i3, |
| uint8_t *attr, int att_len) |
| { |
| struct abis_om_hdr *oh; |
| struct msgb *msg = nm_msgb_alloc(); |
| uint8_t msgtype = NM_MT_SW_ACT_REQ; |
| |
| oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); |
| fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3); |
| |
| if (attr) { |
| uint8_t *ptr = msgb_put(msg, att_len); |
| memcpy(ptr, attr, att_len); |
| } |
| msg->dst = sign_link; |
| return abis_sendmsg(msg); |
| } |
| |
| static int test_bts_gsm_12_21_cb(struct osmo_fd *ofd, unsigned int what) |
| { |
| int ret, event_type; |
| struct ipaccess_unit *unit = ofd->data; |
| |
| if (read(eventfds[0], &event_type, sizeof(unsigned int)) < 0) { |
| LOGP(DBTSTEST, LOGL_ERROR, "error receiving event\n"); |
| return 0; |
| } |
| |
| switch(bts_state) { |
| case BTS_TEST_OML_SIGN_LINK_DOWN: |
| /* Do nothing until OML link becomes ready. */ |
| break; |
| case BTS_TEST_OML_SIGN_LINK_UP: |
| /* OML link is up, send SW ACT REQ. */ |
| ret = abis_nm_sw_act_req(oml_sign_link, 0, |
| unit->bts_id, |
| unit->trx_id, |
| 0, NULL, 0); |
| if (ret < 0) { |
| LOGP(DBTSTEST, LOGL_ERROR, "cannot send SW ACT REQ\n"); |
| break; |
| } |
| bts_state = BTS_TEST_OML_WAIT_SW_ACT_ACK; |
| break; |
| case BTS_TEST_OML_WAIT_SW_ACT_ACK: |
| /* ... things should continue after this. */ |
| break; |
| } |
| return 0; |
| } |
| |
| static struct e1inp_line *line; |
| |
| static void sighandler(int foo) |
| { |
| e1inp_line_put(line); |
| exit(EXIT_SUCCESS); |
| } |
| |
| int main(void) |
| { |
| struct ipaccess_unit bts_dev_info = { |
| .site_id = 1801, |
| .bts_id = 0, |
| .trx_id = 0, |
| .unit_name = "testBTS", |
| .equipvers = "0.1", |
| .swversion = "0.1", |
| .mac_addr = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, |
| .location1 = "testBTS", |
| .location2 = "testBTS", |
| .serno = "", |
| }; |
| |
| tall_test = talloc_named_const(NULL, 1, "e1inp_test"); |
| libosmo_abis_init(tall_test); |
| |
| osmo_init_logging(&bts_test_log_info); |
| |
| struct e1inp_line_ops ops = { |
| .cfg = { |
| .ipa = { |
| .role = E1INP_LINE_R_BTS, |
| .addr = "127.0.0.1", |
| .dev = &bts_dev_info, |
| }, |
| }, |
| .sign_link_up = sign_link_up, |
| .sign_link_down = sign_link_down, |
| .sign_link = sign_link, |
| }; |
| |
| #define LINENR 0 |
| |
| if (signal(SIGINT, sighandler) == SIG_ERR || |
| signal(SIGTERM, sighandler) == SIG_ERR) { |
| perror("Cannot set sighandler"); |
| exit(EXIT_FAILURE); |
| } |
| |
| line = e1inp_line_create(LINENR, "ipa"); |
| if (line == NULL) { |
| LOGP(DBTSTEST, LOGL_ERROR, "problem enabling E1 line\n"); |
| exit(EXIT_FAILURE); |
| } |
| e1inp_line_bind_ops(line, &ops); |
| |
| if (e1inp_line_update(line) < 0) { |
| LOGP(DBTSTEST, LOGL_ERROR, "problem enabling E1 line\n"); |
| exit(EXIT_FAILURE); |
| } |
| |
| LOGP(DBTSTEST, LOGL_NOTICE, "entering main loop\n"); |
| |
| if (pipe(eventfds) < 0) { |
| LOGP(DBTSTEST, LOGL_ERROR, "cannot create pipe fds\n"); |
| exit(EXIT_FAILURE); |
| } |
| bts_eventfd.fd = eventfds[0]; |
| bts_eventfd.cb = test_bts_gsm_12_21_cb; |
| bts_eventfd.when = BSC_FD_READ; |
| bts_eventfd.data = &bts_dev_info; |
| if (osmo_fd_register(&bts_eventfd) < 0) { |
| LOGP(DBTSTEST, LOGL_ERROR, "could not register event fd\n"); |
| exit(EXIT_FAILURE); |
| } |
| |
| while (1) { |
| osmo_select_main(0); |
| } |
| return 0; |
| } |