/** * parse_generic_v6_scn * */ int parse_generic_v6_scn(struct rtas_event *re) { struct rtas_v6_generic *gen; uint32_t copy_sz = sizeof(struct rtas_v6_hdr); gen = malloc(sizeof(*gen)); if (gen == NULL) { errno = ENOMEM; return -1; } memset(gen, 0, sizeof(*gen)); gen->shdr.raw_offset = re->offset; rtas_copy(RE_SHDR_OFFSET(gen), re, copy_sz); if (gen->v6hdr.length > copy_sz) { uint32_t data_sz = gen->v6hdr.length - copy_sz; gen->data = malloc(data_sz); if (gen->data == NULL) { errno = ENOMEM; return -1; } memset(gen->data, 0, data_sz); rtas_copy(gen->data, re, data_sz); } add_re_scn(re, gen, RTAS_GENERIC_SCN); return 0; }
/** * parse_vend_specific_scn * */ int parse_vend_errlog_scn(struct rtas_event *re) { struct rtas_vend_errlog *ve; ve = malloc(sizeof(*ve)); if (ve == NULL) { errno = ENOMEM; return -1; } ve->shdr.raw_offset = re->offset; rtas_copy(RE_SHDR_OFFSET(ve), re, 4); /* See if there is additional data */ ve->vendor_data_sz = re->event_length - re->offset; if (ve->vendor_data_sz > 0) { ve->vendor_data = malloc(ve->vendor_data_sz); if (ve->vendor_data == NULL) { errno = ENOMEM; return -1; } rtas_copy(ve->vendor_data, re, ve->vendor_data_sz); } add_re_scn(re, ve, RTAS_VEND_ERRLOG_SCN); return 0; }
/** * parse_mtms * */ void parse_mtms(struct rtas_event *re, struct rtas_mtms *mtms) { rtas_copy(mtms->model, re, 8); mtms->model[8] = '\0'; rtas_copy(mtms->serial_no, re, 12); mtms->serial_no[12] = '\0'; }
/** * parse_fru_pe_scn * @brief parse a FRU Power Enclosure Identity Substructure * * @param re rtas_event pointer * @returns pointer to parsed rtas_fru_pe_scn, NULL on failure */ static struct rtas_fru_hdr * parse_fru_pe_scn(struct rtas_event *re) { struct rtas_fru_pe_scn *fru_pe; struct rtas_fru_pe_scn_raw *fru_pe_raw; uint32_t scn_sz; char *data; fru_pe = malloc(sizeof(*fru_pe)); if (fru_pe == NULL) { errno = ENOMEM; return NULL; } memset(fru_pe, 0, sizeof(*fru_pe)); fru_pe_raw = (struct rtas_fru_pe_scn_raw *)(re->buffer + re->offset); parse_fru_hdr(&fru_pe->fruhdr, &fru_pe_raw->fruhdr); re->offset += RE_FRU_HDR_SZ; scn_sz = fru_pe->fruhdr.length; data = (char *)fru_pe + sizeof(fru_pe->fruhdr); rtas_copy(data, re, scn_sz - RE_FRU_HDR_SZ); return (struct rtas_fru_hdr *)fru_pe; }
/** * parse_generic_v6_scn * */ int parse_generic_v6_scn(struct rtas_event *re) { struct rtas_v6_generic *gen; struct rtas_v6_hdr_raw *rawhdr; gen = malloc(sizeof(*gen)); if (gen == NULL) { errno = ENOMEM; return -1; } memset(gen, 0, sizeof(*gen)); gen->shdr.raw_offset = re->offset; rawhdr = (struct rtas_v6_hdr_raw *)(re->buffer + re->offset); parse_v6_hdr(&gen->v6hdr, rawhdr); re->offset += RTAS_V6_HDR_SIZE; if (gen->v6hdr.length > RTAS_V6_HDR_SIZE) { uint32_t data_sz = gen->v6hdr.length - RTAS_V6_HDR_SIZE; gen->data = malloc(data_sz); if (gen->data == NULL) { errno = ENOMEM; return -1; } memset(gen->data, 0, data_sz); rtas_copy(gen->data, re, data_sz); } add_re_scn(re, gen, RTAS_GENERIC_SCN); return 0; }
/** * parse_main_a_scn * */ int parse_priv_hdr_scn(struct rtas_event *re) { struct rtas_priv_hdr_scn *privhdr; privhdr = malloc(sizeof(*privhdr)); if (privhdr == NULL) { errno = ENOMEM; return -1; } memset(privhdr, 0, sizeof(*privhdr)); privhdr->shdr.raw_offset = re->offset; /* Copy up through the creator subsection id. Sinc the subsection * id can be ascii we null terminate it then copy the stuff after it. */ rtas_copy(RE_SHDR_OFFSET(privhdr), re, 48); /* If the creator id is 'E', the the subsystem version is in ascii, * copy this info to a null terminated string. */ if (privhdr->creator_id == RTAS_PH_CREAT_SERVICE_PROC) { memcpy(privhdr->creator_subid_name, &privhdr->creator_subid_hi, 8); privhdr->creator_subid_name[8] = '\0'; } add_re_scn(re, privhdr, RTAS_PRIV_HDR_SCN); return 0; }
/** * parse_fru_id_scn * @brief Parse a FRU Identity Substructure * * @param re rtas_event pointer * @returns pointer to parsed rtas_fru_id_scn, NULL on failure */ static struct rtas_fru_hdr * parse_fru_id_scn(struct rtas_event *re) { struct rtas_fru_id_scn *fru_id; struct rtas_fru_id_scn_raw *fru_id_raw; fru_id = malloc(sizeof(*fru_id)); if (fru_id == NULL) { errno = ENOMEM; return NULL; } memset(fru_id, 0, sizeof(*fru_id)); fru_id_raw = (struct rtas_fru_id_scn_raw *)(re->buffer + re->offset); parse_fru_hdr(&fru_id->fruhdr, &fru_id_raw->fruhdr); re->offset += RE_FRU_HDR_SZ; if (fruid_has_part_no(fru_id)) { strcpy(fru_id->part_no, RE_EVENT_OFFSET(re)); re->offset += 8; } if (fruid_has_proc_id(fru_id)) { strcpy(fru_id->procedure_id, RE_EVENT_OFFSET(re)); re->offset += 8; } if (fruid_has_ccin(fru_id)) { rtas_copy(fru_id->ccin, re, 4); fru_id->ccin[4] = '\0'; } if (fruid_has_serial_no(fru_id)) { rtas_copy(fru_id->serial_no, re, 12); fru_id->serial_no[12] = '\0'; } return (struct rtas_fru_hdr *)fru_id; }
/** * parse_ibm diag_scn * */ int parse_ibm_diag_scn(struct rtas_event *re) { struct rtas_ibm_diag_scn *ibmdiag; ibmdiag = malloc(sizeof(*ibmdiag)); if (ibmdiag == NULL) { errno = ENOMEM; return -1; } ibmdiag->shdr.raw_offset = re->offset; rtas_copy(RE_SHDR_OFFSET(ibmdiag), re, sizeof(uint32_t)); add_re_scn(re, ibmdiag, RTAS_IBM_DIAG_SCN); return 0; }
/** * parse_cpu_scn * */ int parse_cpu_scn(struct rtas_event *re) { struct rtas_cpu_scn *cpu_scn; cpu_scn = malloc(sizeof(*cpu_scn)); if (cpu_scn == NULL) { errno = ENOMEM; return -1; } cpu_scn->shdr.raw_offset = re->offset; rtas_copy(RE_SHDR_OFFSET(cpu_scn), re, RE_V4_SCN_SZ); add_re_scn(re, cpu_scn, RTAS_CPU_SCN); return 0; }
/** * parse_usr_hdr_scn * */ int parse_usr_hdr_scn(struct rtas_event *re) { struct rtas_usr_hdr_scn *usrhdr; usrhdr = malloc(sizeof(*usrhdr)); if (usrhdr == NULL) { errno = ENOMEM; return -1; } memset(usrhdr, 0, sizeof(*usrhdr)); usrhdr->shdr.raw_offset = re->offset; rtas_copy(RE_SHDR_OFFSET(usrhdr), re, RE_USR_HDR_SCN_SZ); add_re_scn(re, usrhdr, RTAS_USR_HDR_SCN); return 0; }
/** * parse_mt_scn * */ int parse_mt_scn(struct rtas_event *re) { struct rtas_mt_scn *mt; mt = malloc(sizeof(*mt)); if (mt == NULL) { errno = ENOMEM; return -1; } memset(mt, 0, sizeof(*mt)); mt->shdr.raw_offset = re->offset; rtas_copy(RE_SHDR_OFFSET(mt), re, sizeof(struct rtas_v6_hdr_raw)); parse_mtms(re, &mt->mtms); add_re_scn(re, mt, RTAS_MT_SCN); return 0; }
/** * parse_v6_src_scn * @brief parse a version 6 rtas SRC section * * @param re rtas_event pointer * @param src_start pointer to beginning of SRC section * @return 0 on success, !0 on failure */ int parse_src_scn(struct rtas_event *re) { struct rtas_src_scn *src; struct rtas_src_scn_raw *src_raw; struct rtas_fru_scn *fru, *last_fru; int total_len, srcsub_len; src = malloc(sizeof(*src)); if (src == NULL) { errno = ENOMEM; return 1; } src_raw = malloc(sizeof(*src_raw)); if (src_raw == NULL) { errno = ENOMEM; return 1; } memset(src, 0, sizeof(*src)); memset(src_raw, 0, sizeof(*src_raw)); src->shdr.raw_offset = re->offset; rtas_copy(src_raw, re, RE_SRC_SCN_SZ); parse_v6_hdr(&src->v6hdr, &src_raw->v6hdr); src->version = src_raw->version; memcpy(&src->src_platform_data, &src_raw->src_platform_data, sizeof(src->src_platform_data)); src->ext_refcode2 = be32toh(src_raw->ext_refcode2); src->ext_refcode3 = be32toh(src_raw->ext_refcode3); src->ext_refcode4 = be32toh(src_raw->ext_refcode4); src->ext_refcode5 = be32toh(src_raw->ext_refcode5); src->ext_refcode6 = be32toh(src_raw->ext_refcode6); src->ext_refcode7 = be32toh(src_raw->ext_refcode7); src->ext_refcode8 = be32toh(src_raw->ext_refcode8); src->ext_refcode9 = be32toh(src_raw->ext_refcode9); memcpy(&src->primary_refcode, &src_raw->primary_refcode, sizeof(src->primary_refcode)); add_re_scn(re, src, re_scn_id(&src_raw->v6hdr)); if (!src_subscns_included(src)) return 0; rtas_copy( (char *) src_raw + RE_SRC_SCN_SZ + 4, re, RE_SRC_SUBSCN_SZ); src->subscn_id = src_raw->subscn_id; src->subscn_platform_data = src_raw->subscn_platform_data; src->subscn_length = be16toh(src_raw->subscn_length); srcsub_len = src->subscn_length * 4; /*get number of bytes */ total_len = RE_SRC_SUBSCN_SZ; last_fru = NULL; do { uint32_t fru_len, fru_end; struct rtas_fru_hdr *last_fruhdr = NULL; struct rtas_fru_scn_raw *rawfru; fru = malloc(sizeof(*fru)); if (fru == NULL) { cleanup_rtas_event(re); errno = ENOMEM; return 1; } memset(fru, 0, sizeof(*fru)); rawfru = (struct rtas_fru_scn_raw *)(re->buffer + re->offset); parse_fru_scn(re, fru, rawfru); fru_len = RE_FRU_SCN_SZ + fru->loc_code_length; fru_end = re->offset + fru->length - fru_len; while (re->offset < fru_end) { struct rtas_fru_hdr *cur_fruhdr = NULL; char *id = re->buffer + re->offset; if (strncmp(id, "ID", 2) == 0) cur_fruhdr = parse_fru_id_scn(re); else if (strncmp(id, "PE", 2) == 0) cur_fruhdr = parse_fru_pe_scn(re); else if (strncmp(id, "MR", 2) == 0) cur_fruhdr = parse_fru_mr_scn(re); else { re->offset++; continue; } if (cur_fruhdr == NULL) { cleanup_rtas_event(re); return -1; } if (last_fruhdr == NULL) fru->subscns = cur_fruhdr; else last_fruhdr->next = cur_fruhdr; last_fruhdr = cur_fruhdr; } if (last_fru == NULL) src->fru_scns = fru; else last_fru->next = fru; last_fru = fru; total_len += fru->length; } while (total_len < srcsub_len); return 0; }
/** * parse_rtas_event * @brief parse an rtas event creating a populated rtas_event structure * * @param buf buffer containing the binary RTAS event * @param buflen length of the buffer 'buf' * @return pointer to rtas_event */ struct rtas_event * parse_rtas_event(char *buf, int buflen) { struct rtas_event *re; struct rtas_event_hdr *re_hdr; struct rtas_event_exthdr *rex_hdr; int rc; re = malloc(sizeof(*re)); if (re == NULL) { errno = ENOMEM; return NULL; } memset(re, 0, sizeof(*re)); re->buffer = buf; re->event_no = -1; re_hdr = malloc(sizeof(*re_hdr)); if (re_hdr == NULL) { cleanup_rtas_event(re); errno = ENOMEM; return NULL; } rtas_copy(RE_SHDR_OFFSET(re_hdr), re, RE_EVENT_HDR_SZ); add_re_scn(re, re_hdr, RTAS_EVENT_HDR); /* Validate the length of the buffer passed in. */ re->event_length = re_hdr->ext_log_length + RE_EVENT_HDR_SZ; if (re->event_length > buflen) { cleanup_rtas_event(re); return NULL; } re->version = re_hdr->version; if (re_hdr->extended == 0) return re; rex_hdr = malloc(sizeof(*rex_hdr)); if (rex_hdr == NULL) { cleanup_rtas_event(re); errno = ENOMEM; return NULL; } rtas_copy(RE_SHDR_OFFSET(rex_hdr), re, RE_EXT_HDR_SZ); add_re_scn(re, rex_hdr, RTAS_EVENT_EXT_HDR); if (re_hdr->version == 6) return parse_v6_rtas_event(re); switch (rex_hdr->format_type) { case RTAS_EXTHDR_FMT_CPU: rc = parse_cpu_scn(re); break; case RTAS_EXTHDR_FMT_EPOW: rc = parse_epow_scn(re); break; case RTAS_EXTHDR_FMT_IBM_DIAG: rc = parse_ibm_diag_scn(re); break; case RTAS_EXTHDR_FMT_IO: rc = parse_io_scn(re); break; case RTAS_EXTHDR_FMT_MEMORY: rc = parse_mem_scn(re); break; case RTAS_EXTHDR_FMT_POST: rc = parse_post_scn(re); break; case RTAS_EXTHDR_FMT_IBM_SP: rc = parse_sp_scn(re); break; case RTAS_EXTHDR_FMT_VEND_SPECIFIC_1: case RTAS_EXTHDR_FMT_VEND_SPECIFIC_2: rc = parse_vend_errlog_scn(re); break; default: errno = EFAULT; rc = -1; break; } if ((rc == 0) && (re->offset < re->event_length)) rc = parse_vend_errlog_scn(re); if (rc) { cleanup_rtas_event(re); re = NULL; } return re; }