diff options
Diffstat (limited to 'openbsc/src/abis_nm.c')
-rw-r--r-- | openbsc/src/abis_nm.c | 220 |
1 files changed, 182 insertions, 38 deletions
diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 2dadbb255..2426360ed 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -48,6 +48,7 @@ #define OM_ALLOC_SIZE 1024 #define OM_HEADROOM_SIZE 128 +#define IPACC_SEGMENT_SIZE 245 /* unidirectional messages from BTS to BSC */ static const enum abis_nm_msgtype reports[] = { @@ -541,11 +542,11 @@ static const char *obj_class_name(u_int8_t oc) const char *nm_opstate_name(u_int8_t os) { switch (os) { - case 1: + case NM_OPSTATE_DISABLED: return "Disabled"; - case 2: + case NM_OPSTATE_ENABLED: return "Enabled"; - case 0xff: + case NM_OPSTATE_NULL: return "NULL"; default: return "RFU"; @@ -599,6 +600,13 @@ const char *nm_adm_name(u_int8_t adm) } } +int nm_is_running(struct gsm_nm_state *s) { + return (s->operational == NM_OPSTATE_ENABLED) && ( + (s->availability == NM_AVSTATE_OK) || + (s->availability == 0xff) + ); +} + static void debugp_foh(struct abis_om_fom_hdr *foh) { DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ", @@ -806,19 +814,25 @@ static int abis_nm_rx_statechg_rep(struct msgb *mb) new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS); DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability), new_state.availability); - } + } else + new_state.availability = 0xff; if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) { new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE); DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative)); } DEBUGPC(DNM, "\n"); - if (memcmp(&new_state, nm_state, sizeof(new_state))) { + if ((new_state.administrative != 0 && nm_state->administrative == 0) || + new_state.operational != nm_state->operational || + new_state.availability != nm_state->availability) { /* Update the operational state of a given object in our in-memory data * structures and send an event to the higher layer */ void *obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst); rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state); - *nm_state = new_state; + nm_state->operational = new_state.operational; + nm_state->availability = new_state.availability; + if (nm_state->administrative == 0) + nm_state->administrative = new_state.administrative; } #if 0 if (op_state == 1) { @@ -1036,13 +1050,11 @@ static int abis_nm_rcvmsg_fom(struct msgb *mb) /* check if last message is to be acked */ if (is_ack_nack(nmh->last_msgtype)) { if (mt == MT_ACK(nmh->last_msgtype)) { - fprintf(stderr, "received ACK (0x%x)\n", - foh->msg_type); + DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type); /* we got our ACK, continue sending the next msg */ } else if (mt == MT_NACK(nmh->last_msgtype)) { /* we got a NACK, signal this to the caller */ - fprintf(stderr, "received NACK (0x%x)\n", - foh->msg_type); + DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type); /* FIXME: somehow signal this to the caller */ } else { /* really strange things happen */ @@ -1064,6 +1076,12 @@ static int abis_nm_rcvmsg_fom(struct msgb *mb) case NM_MT_CONN_MDROP_LINK_ACK: DEBUGP(DNM, "CONN MDROP LINK ACK\n"); break; + case NM_MT_IPACC_RESTART_ACK: + dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL); + break; + case NM_MT_IPACC_RESTART_NACK: + dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL); + break; } return 0; @@ -1209,6 +1227,22 @@ struct abis_nm_sw { static struct abis_nm_sw g_sw; +static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg) +{ + if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) { + msgb_v_put(msg, NM_ATT_SW_DESCR); + msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id); + msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len, + sw->file_version); + } else if (sw->bts->type == GSM_BTS_TYPE_BS11) { + msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id); + msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len, + sw->file_version); + } else { + LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n"); + } +} + /* 6.2.1 / 8.3.1: Load Data Initiate */ static int sw_load_init(struct abis_nm_sw *sw) { @@ -1220,11 +1254,8 @@ static int sw_load_init(struct abis_nm_sw *sw) fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class, sw->obj_instance[0], sw->obj_instance[1], sw->obj_instance[2]); - - /* FIXME: this is BS11 specific format */ - msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id); - msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len, - sw->file_version); + + sw_add_file_id_and_ver(sw, msg); msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size); return abis_nm_sendmsg(sw->bts, msg); @@ -1282,7 +1313,24 @@ static int sw_load_segment(struct abis_nm_sw *sw) /* we only now know the exact length for the OM hdr */ len = strlen(line_buf)+2; break; + case GSM_BTS_TYPE_NANOBTS: { + static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough); + len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE); + if (len < 0) { + perror("read failed"); + return -EINVAL; + } + + if (len != IPACC_SEGMENT_SIZE) + sw->last_seg = 1; + + ++sw->seg_in_window; + msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf); + len += 3; + break; + } default: + LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n"); /* FIXME: Other BTS types */ return -1; } @@ -1306,11 +1354,7 @@ static int sw_load_end(struct abis_nm_sw *sw) sw->obj_instance[0], sw->obj_instance[1], sw->obj_instance[2]); - /* FIXME: this is BS11 specific format */ - msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id); - msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len, - sw->file_version); - + sw_add_file_id_and_ver(sw, msg); return abis_nm_sendmsg(sw->bts, msg); } @@ -1334,6 +1378,59 @@ static int sw_activate(struct abis_nm_sw *sw) return abis_nm_sendmsg(sw->bts, msg); } +struct sdp_firmware { + char magic[4]; + char more_magic[4]; + unsigned int header_length; + unsigned int file_length; +} __attribute__ ((packed)); + +static int parse_sdp_header(struct abis_nm_sw *sw) +{ + struct sdp_firmware firmware_header; + int rc; + struct stat stat; + + rc = read(sw->fd, &firmware_header, sizeof(firmware_header)); + if (rc != sizeof(firmware_header)) { + LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n"); + return -1; + } + + if (strncmp(firmware_header.magic, " SDP", 4) != 0) { + LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n"); + return -1; + } + + if (firmware_header.more_magic[0] != 0x10 || + firmware_header.more_magic[1] != 0x02 || + firmware_header.more_magic[2] != 0x00 || + firmware_header.more_magic[3] != 0x00) { + LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n"); + return -1; + } + + + if (fstat(sw->fd, &stat) == -1) { + LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n"); + return -1; + } + + if (ntohl(firmware_header.file_length) != stat.st_size) { + LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n"); + return -1; + } + + /* go back to the start as we checked the whole filesize.. */ + lseek(sw->fd, 0l, SEEK_SET); + LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n" + "There might be checksums in the file that are not\n" + "verified and incomplete firmware might be flashed.\n" + "There is absolutely no WARRANTY that flashing will\n" + "work.\n"); + return 0; +} + static int sw_open_file(struct abis_nm_sw *sw, const char *fname) { char file_id[12+1]; @@ -1365,6 +1462,19 @@ static int sw_open_file(struct abis_nm_sw *sw, const char *fname) /* rewind to start of file */ rewind(sw->stream); break; + case GSM_BTS_TYPE_NANOBTS: + /* TODO: extract that from the filename or content */ + rc = parse_sdp_header(sw); + if (rc < 0) { + fprintf(stderr, "Could not parse the ipaccess SDP header\n"); + return -1; + } + + strcpy((char *)sw->file_id, "id"); + sw->file_id_len = 3; + strcpy((char *)sw->file_version, "version"); + sw->file_version_len = 8; + break; default: /* We don't know how to treat them yet */ close(sw->fd); @@ -1463,6 +1573,12 @@ static int abis_nm_rcvmsg_sw(struct msgb *mb) rc = sw_load_end(sw); } break; + case NM_MT_LOAD_ABORT: + if (sw->cbfn) + sw->cbfn(GSM_HOOK_NM_SWLOAD, + NM_MT_LOAD_ABORT, mb, + sw->cb_data, NULL); + break; } break; case SW_STATE_WAIT_ENDACK: @@ -1476,6 +1592,7 @@ static int abis_nm_rcvmsg_sw(struct msgb *mb) sw->cbfn(GSM_HOOK_NM_SWLOAD, NM_MT_LOAD_END_ACK, mb, sw->cb_data, NULL); + rc = 0; break; case NM_MT_LOAD_END_NACK: if (sw->forced) { @@ -1552,10 +1669,26 @@ int abis_nm_software_load(struct gsm_bts *bts, const char *fname, return -EBUSY; sw->bts = bts; - sw->obj_class = NM_OC_SITE_MANAGER; - sw->obj_instance[0] = 0xff; - sw->obj_instance[1] = 0xff; - sw->obj_instance[2] = 0xff; + + switch (bts->type) { + case GSM_BTS_TYPE_BS11: + sw->obj_class = NM_OC_SITE_MANAGER; + sw->obj_instance[0] = 0xff; + sw->obj_instance[1] = 0xff; + sw->obj_instance[2] = 0xff; + break; + case GSM_BTS_TYPE_NANOBTS: + sw->obj_class = NM_OC_BASEB_TRANSC; + sw->obj_instance[0] = 0x00; + sw->obj_instance[1] = 0x00; + sw->obj_instance[2] = 0xff; + break; + case GSM_BTS_TYPE_UNKNOWN: + default: + LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n"); + return -1; + break; + } sw->window_size = win_size; sw->state = SW_STATE_WAIT_INITACK; sw->cbfn = cbfn; @@ -1583,7 +1716,10 @@ int abis_nm_software_load_status(struct gsm_bts *bts) return rc; } - percent = (ftell(sw->stream) * 100) / st.st_size; + if (sw->stream) + percent = (ftell(sw->stream) * 100) / st.st_size; + else + percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size; return percent; } @@ -2590,9 +2726,10 @@ static int abis_nm_rx_ipacc(struct msgb *msg) struct abis_om_fom_hdr *foh; u_int8_t idstrlen = oh->data[0]; struct tlv_parsed tp; + struct ipacc_ack_signal_data signal; if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) { - DEBUGP(DNM, "id string is not com.ipaccess !?!\n"); + LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n"); return -EINVAL; } @@ -2620,7 +2757,7 @@ static int abis_nm_rx_ipacc(struct msgb *msg) DEBUGPC(DNM, "\n"); break; case NM_MT_IPACC_RSL_CONNECT_NACK: - DEBUGPC(DNM, "RSL CONNECT NACK "); + LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK "); if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES)) DEBUGPC(DNM, " CAUSE=%s\n", nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES))); @@ -2632,35 +2769,35 @@ static int abis_nm_rx_ipacc(struct msgb *msg) /* FIXME: decode and show the actual attributes */ break; case NM_MT_IPACC_SET_NVATTR_NACK: - DEBUGPC(DNM, "SET NVATTR NACK "); + LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK "); if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES)) - DEBUGPC(DNM, " CAUSE=%s\n", + LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n", nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES))); else - DEBUGPC(DNM, "\n"); + LOGPC(DNM, LOGL_ERROR, "\n"); break; case NM_MT_IPACC_GET_NVATTR_ACK: DEBUGPC(DNM, "GET NVATTR ACK\n"); /* FIXME: decode and show the actual attributes */ break; case NM_MT_IPACC_GET_NVATTR_NACK: - DEBUGPC(DNM, "GET NVATTR NACK "); + LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK "); if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES)) - DEBUGPC(DNM, " CAUSE=%s\n", + LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n", nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES))); else - DEBUGPC(DNM, "\n"); + LOGPC(DNM, LOGL_ERROR, "\n"); break; case NM_MT_IPACC_SET_ATTR_ACK: DEBUGPC(DNM, "SET ATTR ACK\n"); break; case NM_MT_IPACC_SET_ATTR_NACK: - DEBUGPC(DNM, "SET ATTR NACK "); + LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK "); if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES)) - DEBUGPC(DNM, " CAUSE=%s\n", + LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n", nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES))); else - DEBUGPC(DNM, "\n"); + LOGPC(DNM, LOGL_ERROR, "\n"); break; default: DEBUGPC(DNM, "unknown\n"); @@ -2672,7 +2809,14 @@ static int abis_nm_rx_ipacc(struct msgb *msg) case NM_MT_IPACC_RSL_CONNECT_NACK: case NM_MT_IPACC_SET_NVATTR_NACK: case NM_MT_IPACC_GET_NVATTR_NACK: - dispatch_signal(SS_NM, S_NM_IPACC_NACK, &foh->msg_type); + signal.bts = msg->trx->bts; + signal.msg_type = foh->msg_type; + dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal); + break; + case NM_MT_IPACC_SET_NVATTR_ACK: + signal.bts = msg->trx->bts; + signal.msg_type = foh->msg_type; + dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal); break; default: break; @@ -2782,7 +2926,7 @@ void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked) { int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED; - trx->rf_locked = locked; + trx->nm_state.administrative = new_state; if (!trx->bts || !trx->bts->oml_link) return; |