From 268bb40b359cf1a74049f3b2264e4e6b5d5a85c6 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 1 Feb 2009 19:11:56 +0000 Subject: [PATCH] * add more detailed status printout to bs11_config * add support for real LMT logon time * add support for abis external time * move 'create_trx1_objects' to separate function --- include/openbsc/abis_nm.h | 17 ++++- src/abis_nm.c | 54 +++++++++++++-- src/bs11_config.c | 141 +++++++++++++++++++++++++++++--------- 3 files changed, 174 insertions(+), 38 deletions(-) diff --git a/include/openbsc/abis_nm.h b/include/openbsc/abis_nm.h index db02ae604..8d8f7cca8 100644 --- a/include/openbsc/abis_nm.h +++ b/include/openbsc/abis_nm.h @@ -403,16 +403,30 @@ enum abis_bs11_trx_power { BS11_TRX_POWER_DCS_160mW= 0x0d, }; -enum abis_bs11_state { +enum abis_bs11_phase { BS11_STATE_SOFTWARE_RQD = 0x01, + BS11_STATE_LOAD_SMU_INTENDED = 0x11, BS11_STATE_LOAD_SMU_SAFETY = 0x21, BS11_STATE_WARM_UP = 0x51, BS11_STATE_WAIT_MIN_CFG = 0x62, BS11_STATE_MAINTENANCE = 0x72, + BS11_STATE_LOAD_MBCCU = 0x92, BS11_STATE_WAIT_MIN_CFG_2 = 0xA2, BS11_STATE_NORMAL = 0x03, }; +struct abis_nm_bs11_state { + u_int8_t unknown; + u_int8_t unknown2; + u_int8_t phase; + u_int8_t mbccu; + u_int8_t unknown3; + u_int8_t ccu; + u_int8_t t_link; + u_int8_t abis_link; +} __attribute__((packed)); + + /* PUBLIC */ struct msgb; @@ -463,5 +477,6 @@ int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password); int abis_nm_bs11_get_state(struct gsm_bts *bts); int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname, u_int8_t win_size, gsm_cbfn *cbfn); +int abis_nm_bs11_set_ext_time(struct gsm_bts *bts); #endif /* _NM_H */ diff --git a/src/abis_nm.c b/src/abis_nm.c index 259132029..c9bea25d9 100644 --- a/src/abis_nm.c +++ b/src/abis_nm.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -836,6 +837,31 @@ int abis_nm_event_reports(struct gsm_bts *bts, int on) /* Siemens (or BS-11) specific commands */ +struct bs11_date_time { + u_int16_t year; + u_int8_t month; + u_int8_t day; + u_int8_t hour; + u_int8_t min; + u_int8_t sec; +} __attribute__((packed)); + + +void get_bs11_date_time(struct bs11_date_time *aet) +{ + time_t t; + struct tm *tm; + + t = time(NULL); + tm = localtime(&t); + aet->sec = tm->tm_sec; + aet->min = tm->tm_min; + aet->hour = tm->tm_hour; + aet->day = tm->tm_mday; + aet->month = tm->tm_mon; + aet->year = htons(1900 + tm->tm_year); +} + int abis_nm_bs11_reset_resource(struct gsm_bts *bts) { return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE); @@ -859,7 +885,7 @@ int abis_nm_bs11_create_object(struct gsm_bts *bts, oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ, - NM_OC_BS11, type, idx, 0); + NM_OC_BS11, type, 0, idx); cur = msgb_put(msg, attr_len); memcpy(cur, attr, attr_len); @@ -936,8 +962,7 @@ int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level) return abis_nm_sendmsg(trx->bts, msg); } -static const u_int8_t bs11_logon_c7[] = - { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 }; +//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 }; static const u_int8_t bs11_logon_c8[] = { 0x02 }; static const u_int8_t bs11_logon_c9[] = "FACTORY"; @@ -945,15 +970,18 @@ int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on) { struct abis_om_hdr *oh; struct msgb *msg = nm_msgb_alloc(); + struct bs11_date_time bdt; + + get_bs11_date_time(&bdt); oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); if (on) { - u_int8_t len = 3*2 + sizeof(bs11_logon_c7) + u_int8_t len = 3*2 + sizeof(bdt) + sizeof(bs11_logon_c8) + sizeof(bs11_logon_c9); fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON, NM_OC_BS11_A3, 0xff, 0xff, 0xff); msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME, - sizeof(bs11_logon_c7), bs11_logon_c7); + sizeof(bdt), &bdt); msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV, sizeof(bs11_logon_c8), bs11_logon_c8); msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME, @@ -1182,3 +1210,19 @@ int abis_nm_bs11_get_serno(struct gsm_bts *bts) return abis_nm_sendmsg(bts, msg); } + +int abis_nm_bs11_set_ext_time(struct gsm_bts *bts) +{ + struct abis_om_hdr *oh; + struct msgb *msg = nm_msgb_alloc(); + struct bs11_date_time aet; + + get_bs11_date_time(&aet); + oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); + /* SiemensHW CCTRL object */ + fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER, + 0xff, 0xff, 0xff); + msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), &aet); + + return abis_nm_sendmsg(bts, msg); +} diff --git a/src/bs11_config.c b/src/bs11_config.c index 6166c8414..af73d23ae 100644 --- a/src/bs11_config.c +++ b/src/bs11_config.c @@ -81,6 +81,27 @@ static struct serial_handle _ser_handle, *ser_handle = &_ser_handle; static int handle_serial_msg(struct msgb *rx_msg); +static int create_trx1_objects(struct gsm_bts *bts) +{ + u_int8_t bbsig1_attr[sizeof(obj_bbsig0_attr)+12]; + u_int8_t *cur = bbsig1_attr; + + abis_nm_bs11_set_trx1_pw(bts, trx1_password); + + cur = tlv_put(cur, NM_ATT_BS11_PASSWORD, 10, + (u_int8_t *)trx1_password); + memcpy(cur, obj_bbsig0_attr, sizeof(obj_bbsig0_attr)); + abis_nm_bs11_create_object(bts, BS11_OBJ_BBSIG, 1, + sizeof(bbsig1_attr), bbsig1_attr); + + abis_nm_bs11_create_object(bts, BS11_OBJ_PA, 1, + sizeof(obj_pa0_attr), obj_pa0_attr); + + abis_nm_bs11_set_trx_power(&bts->trx[1], BS11_TRX_POWER_GSM_30mW); + + return 0; +} + /* create all objects for an initial configuration */ static int create_objects(struct gsm_bts *bts, int trx1) { @@ -94,22 +115,6 @@ static int create_objects(struct gsm_bts *bts, int trx1) sizeof(obj_bbsig0_attr), obj_bbsig0_attr); abis_nm_bs11_create_object(bts, BS11_OBJ_PA, 0, sizeof(obj_pa0_attr), obj_pa0_attr); - if (trx1) { - u_int8_t bbsig1_attr[sizeof(obj_bbsig0_attr)+12]; - u_int8_t *cur = bbsig1_attr; - - abis_nm_bs11_set_trx1_pw(bts, trx1_password); - - cur = tlv_put(cur, NM_ATT_BS11_PASSWORD, 10, - (u_int8_t *)trx1_password); - memcpy(cur, obj_bbsig0_attr, sizeof(obj_bbsig0_attr)); - abis_nm_bs11_create_object(bts, BS11_OBJ_BBSIG, 1, - sizeof(bbsig1_attr), bbsig1_attr); - - abis_nm_bs11_create_object(bts, BS11_OBJ_PA, 1, - sizeof(obj_pa0_attr), obj_pa0_attr); - } - abis_nm_bs11_create_envaBTSE(bts, 0); abis_nm_bs11_create_envaBTSE(bts, 1); abis_nm_bs11_create_envaBTSE(bts, 2); @@ -119,10 +124,6 @@ static int create_objects(struct gsm_bts *bts, int trx1) abis_nm_bs11_set_oml_tei(bts, TEI_OML); abis_nm_bs11_set_trx_power(&bts->trx[0], BS11_TRX_POWER_GSM_30mW); - - if (trx1) - abis_nm_bs11_set_trx_power(&bts->trx[1], BS11_TRX_POWER_GSM_30mW); - //abis_nm_bs11_factory_logon(bts, 0); return 0; @@ -336,24 +337,99 @@ static int swload_cbfn(unsigned int hook, unsigned int event, struct msgb *msg, return 0; } -/* handle a response from the BTS to a GET STATE command */ -static int handle_state_resp(u_int8_t state) +static const char *bs11_link_state[] = { + [0x00] = "Down", + [0x01] = "Up", + [0x02] = "Restoring", +}; + +static const char *linkstate_name(u_int8_t linkstate) { - int rc = 0; + if (linkstate > ARRAY_SIZE(bs11_link_state)) + return "Unknown"; - printf("STATE: "); + return bs11_link_state[linkstate]; +} - switch (state) { +static const char *mbccu_load[] = { + [0] = "No Load", + [1] = "Load BTSCAC", + [2] = "Load BTSDRX", + [3] = "Load BTSBBX", + [4] = "Load BTSARC", + [5] = "Load", +}; + +static const char *mbccu_load_name(u_int8_t linkstate) +{ + if (linkstate > ARRAY_SIZE(mbccu_load)) + return "Unknown"; + + return mbccu_load[linkstate]; +} + + +static void print_state(struct abis_nm_bs11_state *st) +{ + enum abis_bs11_phase phase = st->phase; + + printf("T-Link: %-9s Abis-link: %-9s MBCCU0: %-11s MBCCU1: %-11s PHASE: %u SUBPHASE: ", + linkstate_name(st->t_link), linkstate_name(st->abis_link), + mbccu_load_name(st->mbccu >> 4), mbccu_load_name(st->mbccu & 0xf), + phase & 0xf); + + switch (phase) { case BS11_STATE_WARM_UP: printf("Warm Up...\n"); - sleep(5); break; case BS11_STATE_LOAD_SMU_SAFETY: printf("Load SMU Safety...\n"); - sleep(5); + break; + case BS11_STATE_LOAD_SMU_INTENDED: + printf("Load SMU Intended...\n"); + break; + case BS11_STATE_LOAD_MBCCU: + printf("Load MBCCU...\n"); break; case BS11_STATE_SOFTWARE_RQD: printf("Software required...\n"); + break; + case BS11_STATE_WAIT_MIN_CFG: + case BS11_STATE_WAIT_MIN_CFG_2: + printf("Wait minimal config...\n"); + break; + case BS11_STATE_MAINTENANCE: + printf("Maintenance...\n"); + break; + case BS11_STATE_NORMAL: + printf("Normal...\n"); + break; + default: + printf("Unknown phase 0x%02x\n", phase); + break; + } +} + +/* handle a response from the BTS to a GET STATE command */ +static int handle_state_resp(enum abis_bs11_phase state) +{ + int rc = 0; + + printf("PHASE: %u STATE: ", state & 0xf); + + switch (state) { + case BS11_STATE_WARM_UP: + sleep(5); + break; + case BS11_STATE_LOAD_SMU_SAFETY: + sleep(5); + break; + case BS11_STATE_LOAD_SMU_INTENDED: + sleep(5); + break; + case BS11_STATE_LOAD_MBCCU: + break; + case BS11_STATE_SOFTWARE_RQD: bs11cfg_state = STATE_SWLOAD; /* send safety load. Use g_bts as private 'param' * argument, so our swload_cbfn can distinguish @@ -368,12 +444,10 @@ static int handle_state_resp(u_int8_t state) break; case BS11_STATE_WAIT_MIN_CFG: case BS11_STATE_WAIT_MIN_CFG_2: - printf("Wait minimal config...\n"); bs11cfg_state = STATE_SWLOAD; rc = create_objects(g_bts, have_trx1); break; case BS11_STATE_MAINTENANCE: - printf("Maintenance...\n"); bs11cfg_state = STATE_SWLOAD; /* send software (FIXME: over A-bis?) */ if (file_is_readable(fname_software)) @@ -384,10 +458,10 @@ static int handle_state_resp(u_int8_t state) fname_software); break; case BS11_STATE_NORMAL: - printf("Normal...\n"); + if (have_trx1) + create_trx1_objects(g_bts); return 1; default: - printf("Unknown state 0x%02u\n", state); sleep(5); break; } @@ -399,6 +473,7 @@ static int handle_serial_msg(struct msgb *rx_msg) { struct abis_om_hdr *oh; struct abis_om_fom_hdr *foh; + struct abis_nm_bs11_state *st; int rc = -1; if (rx_msg->len < LAPD_HDR_LEN @@ -427,7 +502,9 @@ static int handle_serial_msg(struct msgb *rx_msg) exit(0); break; case NM_MT_BS11_GET_STATE_ACK: - rc = handle_state_resp(foh->data[2]); + st = (struct abis_nm_bs11_state *) &foh->data[0]; + print_state(st); + rc = handle_state_resp(st->phase); break; default: rc = abis_nm_rcvmsg(rx_msg);