예제 #1
0
static int
dissect_ipmi_cmd(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
		gint hf_parent_item, gint ett_tree, const ipmi_context_t * ctx)
{
	ipmi_packet_data_t * data;
	ipmi_netfn_t * cmd_list;
	ipmi_cmd_t * cmd;
	proto_item * ti;
	proto_tree * cmd_tree = NULL, * tmp_tree;
	guint8 prev_level, cc_val;
	guint offset, siglen, is_resp;
	const char * cc_str, * netfn_str;

	/* get packet data */
	data = get_packet_data(pinfo);
	if (!data) {
		return 0;
	}

	/* get prefix length */
	siglen = ipmi_getsiglen(ctx->hdr.netfn);

	/* get response flag */
	is_resp = ctx->hdr.netfn & 1;

	/* check message length */
	if (tvb_captured_length(tvb) < ctx->hdr_len + siglen + is_resp
			+ !(ctx->flags & IPMI_D_NO_CKS)) {
		/* don bother with anything */
		return call_data_dissector(tvb, pinfo, tree);
	}

	/* save nest level */
	prev_level = data->curr_level;

	/* assign next nest level */
	data->curr_level = data->next_level;

	/* increment next nest level */
	data->next_level++;

	/* check for the first invocation */
	if (!data->curr_level) {
		/* get current frame data */
		data->curr_frame = get_frame_data(data, pinfo->num);
		data->curr_frame_num = pinfo->num;

		/* copy frame timestamp */
		memcpy(&data->curr_frame->ts, &pinfo->abs_ts, sizeof(nstime_t));

		/* cache channel and direction */
		data->curr_channel = ctx->hdr.channel;
		data->curr_dir = ctx->hdr.dir;

		/* remove requests which are too old */
		remove_old_requests(data, &pinfo->abs_ts);
	}

	if (data->curr_level < MAX_NEST_LEVEL) {
		if (ctx->hdr.netfn & 1) {
			/* perform request/response matching */
			match_request_response(data, &ctx->hdr, ctx->flags);
		} else {
			/* add request to the list for later matching */
			add_request(data, &ctx->hdr);
		}
	}

	/* get command list by network function code */
	cmd_list = ipmi_getnetfn(ctx->hdr.netfn,
			tvb_get_ptr(tvb, ctx->hdr_len + is_resp, siglen));

	/* get command descriptor */
	cmd = ipmi_getcmd(cmd_list, ctx->hdr.cmd);

	/* check if response */
	if (is_resp) {
		/* get completion code */
		cc_val = tvb_get_guint8(tvb, ctx->hdr_len);

		/* get completion code desc */
		cc_str = ipmi_get_completion_code(cc_val, cmd);
	} else {
		cc_val = 0;
		cc_str = NULL;
	}

	/* check if not inside a message */
	if (!data->curr_level) {
		/* add packet info */
		add_command_info(pinfo, cmd, is_resp, cc_val, cc_str,
				ctx->flags & IPMI_D_BROADCAST ? TRUE : FALSE);
	}

	if (tree) {
		/* add parent node */
		if (!data->curr_level) {
			ti = proto_tree_add_item(tree, hf_parent_item, tvb, 0, -1, ENC_NA);
			cmd_tree = proto_item_add_subtree(ti, ett_tree);
		} else {
			char str[ITEM_LABEL_LENGTH];

			if (is_resp) {
				g_snprintf(str, ITEM_LABEL_LENGTH, "Rsp, %s, %s",
						cmd->desc, cc_str);
			} else {
				g_snprintf(str, ITEM_LABEL_LENGTH, "Req, %s", cmd->desc);
			}
			if (proto_registrar_get_ftype(hf_parent_item) == FT_STRING) {
				ti = proto_tree_add_string(tree, hf_parent_item, tvb, 0, -1, str);
				cmd_tree = proto_item_add_subtree(ti, ett_tree);
			}
			else
				cmd_tree = proto_tree_add_subtree(tree, tvb, 0, -1, ett_tree, NULL, str);
		}

		if (data->curr_level < MAX_NEST_LEVEL) {
			/* check if response */
			if (ctx->hdr.netfn & 1) {
				/* get current command data */
				ipmi_cmd_data_t * rs_data =
						data->curr_frame->cmd_data[data->curr_level];

				if (rs_data->matched_frame_num) {
					nstime_t ns;

					/* add "Request to:" field */
					ti = proto_tree_add_uint(cmd_tree, hf_ipmi_response_to,
							tvb, 0, 0, rs_data->matched_frame_num);

					/* mark field as a generated one */
					PROTO_ITEM_SET_GENERATED(ti);

					/* calculate delta time */
					nstime_delta(&ns, &pinfo->abs_ts,
							&get_frame_data(data,
									rs_data->matched_frame_num)->ts);

					/* add "Response time" field */
					ti = proto_tree_add_time(cmd_tree, hf_ipmi_response_time,
							tvb, 0, 0, &ns);

					/* mark field as a generated one */
					PROTO_ITEM_SET_GENERATED(ti);
					}
			} else {
				/* get current command data */
				ipmi_cmd_data_t * rq_data =
						data->curr_frame->cmd_data[data->curr_level];

				if (rq_data->matched_frame_num) {
					/* add "Response in:" field  */
					ti = proto_tree_add_uint(cmd_tree, hf_ipmi_response_in,
							tvb, 0, 0, rq_data->matched_frame_num);

					/* mark field as a generated one */
					PROTO_ITEM_SET_GENERATED(ti);
				}
			}
		}

		/* set starting offset */
		offset = 0;

		/* check if message is broadcast */
		if (ctx->flags & IPMI_D_BROADCAST) {
			/* skip first byte */
			offset++;
		}

		/* check if session handle is specified */
		if (ctx->flags & IPMI_D_SESSION_HANDLE) {
			/* add session handle field */
			proto_tree_add_item(cmd_tree, hf_ipmi_session_handle,
					tvb, offset++, 1, ENC_LITTLE_ENDIAN);
		}

		/* check if responder address is specified */
		if (ctx->flags & IPMI_D_TRG_SA) {
			/* add response address field */
			proto_tree_add_item(cmd_tree, hf_ipmi_header_trg, tvb,
					offset++, 1, ENC_LITTLE_ENDIAN);
		}

		/* get NetFn string */
		netfn_str = ipmi_getnetfnname(ctx->hdr.netfn, cmd_list);

		/* Network function + target LUN */
		tmp_tree = proto_tree_add_subtree_format(cmd_tree, tvb, offset, 1,
				ett_header_byte_1, NULL, "Target LUN: 0x%02x, NetFN: %s %s (0x%02x)",
				ctx->hdr.rs_lun, netfn_str,
				is_resp ? "Response" : "Request", ctx->hdr.netfn);

		/* add Net Fn */
		proto_tree_add_uint_format(tmp_tree, hf_ipmi_header_netfn, tvb,
				offset, 1, ctx->hdr.netfn << 2,
				"NetFn: %s %s (0x%02x)", netfn_str,
				is_resp ? "Response" : "Request", ctx->hdr.netfn);

		proto_tree_add_item(tmp_tree, hf_ipmi_header_trg_lun, tvb,
				offset++, 1, ENC_LITTLE_ENDIAN);

		/* check if cks1 is specified */
		if (!(ctx->flags & IPMI_D_NO_CKS)) {
			guint8 cks = tvb_get_guint8(tvb, offset);

			/* Header checksum */
			if (ctx->cks1) {
				guint8 correct = cks - ctx->cks1;

				proto_tree_add_uint_format_value(cmd_tree, hf_ipmi_header_crc,
						tvb, offset++, 1, cks,
						"0x%02x (incorrect, expected 0x%02x)", cks, correct);
			} else {
				proto_tree_add_uint_format_value(cmd_tree, hf_ipmi_header_crc,
						tvb, offset++, 1, cks,
						"0x%02x (correct)", cks);
			}
		}

		/* check if request address is specified */
		if (!(ctx->flags & IPMI_D_NO_RQ_SA)) {
			/* add request address field */
			proto_tree_add_item(cmd_tree, hf_ipmi_header_src, tvb,
					offset++, 1, ENC_LITTLE_ENDIAN);
		}

		/* check if request sequence is specified */
		if (!(ctx->flags & IPMI_D_NO_SEQ)) {
			/* Sequence number + source LUN */
			tmp_tree = proto_tree_add_subtree_format(cmd_tree, tvb, offset, 1,
					ett_header_byte_4, NULL, "%s: 0x%02x, SeqNo: 0x%02x",
					(ctx->flags & IPMI_D_TMODE) ? "Bridged" : "Source LUN",
							ctx->hdr.rq_lun, ctx->hdr.rq_seq);

			if (ctx->flags & IPMI_D_TMODE) {
				proto_tree_add_item(tmp_tree, hf_ipmi_header_bridged,
						tvb, offset, 1, ENC_LITTLE_ENDIAN);
			} else {
				proto_tree_add_item(tmp_tree, hf_ipmi_header_src_lun,
						tvb, offset, 1, ENC_LITTLE_ENDIAN);
			}

			/* print seq no */
			proto_tree_add_item(tmp_tree, hf_ipmi_header_sequence, tvb,
					offset++, 1, ENC_LITTLE_ENDIAN);
		}

		/* command code */
		proto_tree_add_uint_format_value(cmd_tree, hf_ipmi_header_command,
				tvb, offset++, 1, ctx->hdr.cmd, "%s (0x%02x)",
				cmd->desc, ctx->hdr.cmd);

		if (is_resp) {
			/* completion code */
			proto_tree_add_uint_format_value(cmd_tree,
					hf_ipmi_header_completion, tvb, offset++, 1,
					cc_val, "%s (0x%02x)", cc_str, cc_val);
		}

		if (siglen) {
			/* command prefix (if present) */
			ti = proto_tree_add_item(cmd_tree, hf_ipmi_header_sig, tvb,
					offset, siglen, ENC_NA);
			proto_item_append_text(ti, " (%s)", netfn_str);
		}
	}

	if (tree || (cmd->flags & CMD_CALLRQ)) {
		/* calculate message data length */
		guint data_len = tvb_captured_length(tvb)
				- ctx->hdr_len
				- siglen
				- (is_resp ? 1 : 0)
				- !(ctx->flags & IPMI_D_NO_CKS);

		/* create data subset */
		tvbuff_t * data_tvb = tvb_new_subset_length(tvb,
				ctx->hdr_len + siglen + (is_resp ? 1 : 0), data_len);

		/* Select sub-handler */
		ipmi_cmd_handler_t hnd = is_resp ? cmd->parse_resp : cmd->parse_req;

		if (hnd && tvb_captured_length(data_tvb)) {
			/* create data field */
			tmp_tree = proto_tree_add_subtree(cmd_tree, data_tvb, 0, -1, ett_data, NULL, "Data");

			/* save current command */
			data->curr_hdr = &ctx->hdr;

			/* save current completion code */
			data->curr_ccode = cc_val;

			/* call command parser */
			hnd(data_tvb, pinfo, tmp_tree);
		}
	}

	/* check if cks2 is specified */
	if (tree && !(ctx->flags & IPMI_D_NO_CKS)) {
		guint8 cks;

		/* get cks2 offset */
		offset = tvb_captured_length(tvb) - 1;

		/* get cks2 */
		cks = tvb_get_guint8(tvb, offset);

		/* Header checksum */
		if (ctx->cks2) {
			guint8 correct = cks - ctx->cks2;

			proto_tree_add_uint_format_value(cmd_tree, hf_ipmi_data_crc,
					tvb, offset, 1, cks,
					"0x%02x (incorrect, expected 0x%02x)", cks, correct);
		} else {
			proto_tree_add_uint_format_value(cmd_tree, hf_ipmi_data_crc,
					tvb, offset, 1, cks,
					"0x%02x (correct)", cks);
		}
	}

	/* decrement next nest level */
	data->next_level = data->curr_level;

	/* restore previous nest level */
	data->curr_level = prev_level;

	return tvb_captured_length(tvb);
}
예제 #2
0
// Adapted from get_it_value in gtk/io_stat.c.
double get_io_graph_item(const io_graph_item_t *items_, io_graph_item_unit_t val_units_, int idx, int hf_index_, const capture_file *cap_file, int interval_, int cur_idx_)
{
    double     value = 0;          /* FIXME: loss of precision, visible on the graph for small values */
    int        adv_type;
    const io_graph_item_t *item;
    guint32    interval;

    item = &items_[idx];

    // Basic units
    switch (val_units_) {
    case IOG_ITEM_UNIT_PACKETS:
        return item->frames;
    case IOG_ITEM_UNIT_BYTES:
        return (double) item->bytes;
    case IOG_ITEM_UNIT_BITS:
        return (double) (item->bytes * 8);
    case IOG_ITEM_UNIT_CALC_FRAMES:
        return item->frames;
    case IOG_ITEM_UNIT_CALC_FIELDS:
        return (double) item->fields;
    default:
        /* If it's COUNT_TYPE_ADVANCED but not one of the
         * generic ones we'll get it when we switch on the
         * adv_type below. */
        break;
    }

    if (hf_index_ < 0) {
        return 0;
    }
    // Advanced units
    adv_type = proto_registrar_get_ftype(hf_index_);
    switch (adv_type) {
    case FT_UINT8:
    case FT_UINT16:
    case FT_UINT24:
    case FT_UINT32:
    case FT_UINT64:
    case FT_INT8:
    case FT_INT16:
    case FT_INT24:
    case FT_INT32:
    case FT_INT64:
        switch (val_units_) {
        case IOG_ITEM_UNIT_CALC_SUM:
            value = (double) item->int_tot;
            break;
        case IOG_ITEM_UNIT_CALC_MAX:
            value = (double) item->int_max;
            break;
        case IOG_ITEM_UNIT_CALC_MIN:
            value = (double) item->int_min;
            break;
        case IOG_ITEM_UNIT_CALC_AVERAGE:
            if (item->fields) {
                value = (double)item->int_tot / item->fields;
            } else {
                value = 0;
            }
            break;
        default:
            break;
        }
        break;
    case FT_FLOAT:
        switch (val_units_) {
        case IOG_ITEM_UNIT_CALC_SUM:
            value = item->float_tot;
            break;
        case IOG_ITEM_UNIT_CALC_MAX:
            value = item->float_max;
            break;
        case IOG_ITEM_UNIT_CALC_MIN:
            value = item->float_min;
            break;
        case IOG_ITEM_UNIT_CALC_AVERAGE:
            if (item->fields) {
                value = (double)item->float_tot / item->fields;
            } else {
                value = 0;
            }
            break;
        default:
            break;
        }
        break;
    case FT_DOUBLE:
        switch (val_units_) {
        case IOG_ITEM_UNIT_CALC_SUM:
            value = item->double_tot;
            break;
        case IOG_ITEM_UNIT_CALC_MAX:
            value = item->double_max;
            break;
        case IOG_ITEM_UNIT_CALC_MIN:
            value = item->double_min;
            break;
        case IOG_ITEM_UNIT_CALC_AVERAGE:
            if (item->fields) {
                value = item->double_tot / item->fields;
            } else {
                value = 0;
            }
            break;
        default:
            break;
        }
        break;
    case FT_RELATIVE_TIME:
        switch (val_units_) {
        case IOG_ITEM_UNIT_CALC_MAX:
            value = nstime_to_sec(&item->time_max);
            break;
        case IOG_ITEM_UNIT_CALC_MIN:
            value = nstime_to_sec(&item->time_min);
            break;
        case IOG_ITEM_UNIT_CALC_SUM:
            value = nstime_to_sec(&item->time_tot);
            break;
        case IOG_ITEM_UNIT_CALC_AVERAGE:
            if (item->fields) {
                value = nstime_to_sec(&item->time_tot) / item->fields;
            } else {
                value = 0;
            }
            break;
        case IOG_ITEM_UNIT_CALC_LOAD:
            // "LOAD graphs plot the QUEUE-depth of the connection over time"
            // (for response time fields such as smb.time, rpc.time, etc.)
            // This interval is expressed in milliseconds.
            if (idx == cur_idx_ && cap_file) {
                interval = (guint32)(nstime_to_msec(&cap_file->elapsed_time) + 0.5);
                interval -= (interval_ * idx);
            } else {
                interval = interval_;
            }
            value = nstime_to_msec(&item->time_tot) / interval;
            break;
        default:
            break;
        }
        break;
    default:
        break;
    }
    return value;
}