static void dissect_btobex(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_item *ti; proto_tree *st; fragment_data *frag_msg = NULL; gboolean save_fragmented, complete; tvbuff_t* new_tvb = NULL; tvbuff_t* next_tvb = NULL; guint32 no_of_segments = 0; int offset = 0; save_fragmented = pinfo->fragmented; frag_msg = NULL; complete = FALSE; if (fragment_get(pinfo, pinfo->p2p_dir, fragment_table)) { /* not the first fragment */ frag_msg = fragment_add_seq_next(tvb, 0, pinfo, pinfo->p2p_dir, fragment_table, reassembled_table, tvb_length(tvb), TRUE); new_tvb = process_reassembled_data(tvb, 0, pinfo, "Reassembled Obex packet", frag_msg, &btobex_frag_items, NULL, tree); pinfo->fragmented = TRUE; } else { if (tvb_length(tvb) < tvb_get_ntohs(tvb, offset+1)) { /* first fragment in a sequence */ no_of_segments = tvb_get_ntohs(tvb, offset+1)/tvb_length(tvb); if (tvb_get_ntohs(tvb, offset+1) > (no_of_segments * tvb_length(tvb))) no_of_segments++; frag_msg = fragment_add_seq_next(tvb, 0, pinfo, pinfo->p2p_dir, fragment_table, reassembled_table, tvb_length(tvb), TRUE); fragment_set_tot_len(pinfo, pinfo->p2p_dir, fragment_table, no_of_segments-1); new_tvb = process_reassembled_data(tvb, 0, pinfo, "Reassembled Obex packet", frag_msg, &btobex_frag_items, NULL, tree); pinfo->fragmented = TRUE; } else if (tvb_length(tvb) == tvb_get_ntohs(tvb, offset+1)) { /* non-fragmented */ complete = TRUE; pinfo->fragmented = FALSE; } } if (new_tvb) { /* take it all */ next_tvb = new_tvb; complete = TRUE; } else { /* make a new subset */ next_tvb = tvb_new_subset_remaining(tvb, offset); } if (complete) { guint8 code, final_flag; /* fully dissectable packet ready */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "OBEX"); ti = proto_tree_add_item(tree, proto_btobex, next_tvb, 0, -1, ENC_NA); st = proto_item_add_subtree(ti, ett_btobex); /* op/response code */ code = tvb_get_guint8(next_tvb, offset) & BTOBEX_CODE_VALS_MASK; final_flag = tvb_get_guint8(next_tvb, offset) & 0x80; switch (pinfo->p2p_dir) { case P2P_DIR_SENT: col_add_fstr(pinfo->cinfo, COL_INFO, "Sent "); break; case P2P_DIR_RECV: col_add_fstr(pinfo->cinfo, COL_INFO, "Rcvd "); break; case P2P_DIR_UNKNOWN: break; default: col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown direction %d ", pinfo->p2p_dir); break; } col_append_fstr(pinfo->cinfo, COL_INFO, "%s", val_to_str_ext_const(code, &code_vals_ext, "Unknown")); if ((code < BTOBEX_CODE_VALS_CONTINUE) || (code == BTOBEX_CODE_VALS_ABORT)) { proto_tree_add_item(st, hf_opcode, next_tvb, offset, 1, ENC_BIG_ENDIAN); if (pinfo->p2p_dir == P2P_DIR_SENT || pinfo->p2p_dir == P2P_DIR_RECV) { last_opcode[pinfo->p2p_dir] = code; } } else { proto_tree_add_item(st, hf_response_code, next_tvb, offset, 1, ENC_BIG_ENDIAN); } proto_tree_add_item(st, hf_final_flag, next_tvb, offset, 1, ENC_BIG_ENDIAN); offset++; /* length */ proto_tree_add_item(st, hf_length, next_tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; switch(code) { case BTOBEX_CODE_VALS_CONNECT: proto_tree_add_item(st, hf_version, next_tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item(st, hf_flags, next_tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item(st, hf_max_pkt_len, next_tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; break; case BTOBEX_CODE_VALS_PUT: case BTOBEX_CODE_VALS_GET: col_append_fstr(pinfo->cinfo, COL_INFO, " %s", (final_flag == 0x80) ? "final" : "continue"); break; case BTOBEX_CODE_VALS_SET_PATH: proto_tree_add_item(st, hf_flags, next_tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(st, hf_set_path_flags_0, next_tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(st, hf_set_path_flags_1, next_tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item(st, hf_constants, next_tvb, offset, 1, ENC_BIG_ENDIAN); offset++; break; case BTOBEX_CODE_VALS_DISCONNECT: case BTOBEX_CODE_VALS_ABORT: break; default: { guint8 response_opcode = last_opcode[(pinfo->p2p_dir + 1) & 0x01]; if (response_opcode == BTOBEX_CODE_VALS_CONNECT) { proto_tree_add_item(st, hf_version, next_tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item(st, hf_flags, next_tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item(st, hf_max_pkt_len, next_tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; } } break; } dissect_headers(st, next_tvb, offset, pinfo); } else { /* packet fragment */ col_add_fstr(pinfo->cinfo, COL_INFO, "%s Obex fragment", (pinfo->p2p_dir==P2P_DIR_SENT) ? "Sent" : "Rcvd"); call_dissector(data_handle, next_tvb, pinfo, tree); } pinfo->fragmented = save_fragmented; }
static gboolean dissect_dcc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *dcc_tree, *dcc_optree, *dcc_opnumtree, *ti; proto_tree *dcc_tracetree; proto_item *hidden_item; int offset = 0; int client_is_le = 0; int op = 0; int i, is_response; if (pinfo->srcport != DCC_PORT && pinfo->destport != DCC_PORT) { /* Not the right port - not a DCC packet. */ return FALSE; } /* get at least a full packet structure */ if ( tvb_length(tvb) < sizeof(DCC_HDR) ) { /* Doesn't have enough bytes to contain packet header. */ return FALSE; } col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCC"); offset = 0; is_response = pinfo->srcport == DCC_PORT; if (check_col(pinfo->cinfo, COL_INFO)) { col_add_fstr(pinfo->cinfo, COL_INFO, "%s: %s", is_response ? "Response" : "Request", val_to_str(tvb_get_guint8(tvb, offset+3), dcc_op_vals, "Unknown Op: %u") ); } if (tree) { ti = proto_tree_add_item(tree, proto_dcc, tvb, offset, -1, FALSE); dcc_tree = proto_item_add_subtree(ti, ett_dcc); proto_tree_add_item(dcc_tree, hf_dcc_len, tvb, offset, 2, FALSE); if ( tvb_length(tvb) < tvb_get_ntohs(tvb, offset)) { /* Doesn't have number of bytes that header claims. */ proto_tree_add_text(dcc_tree, tvb, offset, 2, "Error - packet is shorter than header claims!"); } offset += 2; proto_tree_add_item(dcc_tree, hf_dcc_pkt_vers, tvb, offset, 1, FALSE); offset += 1; op = tvb_get_guint8(tvb, offset); proto_tree_add_item(dcc_tree, hf_dcc_op, tvb, offset, 1, FALSE); offset += 1; proto_tree_add_item(dcc_tree, hf_dcc_clientid, tvb, offset, 4, FALSE); offset += 4; ti = proto_tree_add_text(dcc_tree, tvb, offset, -1, "Operation Numbers (Opaque to Server)"); dcc_opnumtree = proto_item_add_subtree(ti, ett_dcc_opnums); /* Note - these are indeterminate - they are sortof considered opaque to the client */ /* Make some attempt to figure out if this data is little endian, not guaranteed to be correct if connection went through a firewall or similar. */ /* Very hokey check - if all three of pid/report/retrans look like little-endian numbers, host is probably little endian. Probably innacurate on super-heavily-used DCC clients though. This should be good enough for now. */ client_is_le = ( (tvb_get_guint8(tvb, offset+4) | tvb_get_guint8(tvb, offset+4)) && (tvb_get_guint8(tvb, offset+8) | tvb_get_guint8(tvb, offset+9)) && (tvb_get_guint8(tvb, offset+12) | tvb_get_guint8(tvb, offset+13)) ); proto_tree_add_item(dcc_opnumtree, hf_dcc_opnums_host, tvb, offset, 4, client_is_le); offset += 4; proto_tree_add_item(dcc_opnumtree, hf_dcc_opnums_pid, tvb, offset, 4, client_is_le); offset += 4; proto_tree_add_item(dcc_opnumtree, hf_dcc_opnums_report, tvb, offset, 4, client_is_le); offset += 4; proto_tree_add_item(dcc_opnumtree, hf_dcc_opnums_retrans, tvb, offset, 4, client_is_le); offset += 4; ti = proto_tree_add_text(dcc_tree, tvb, offset, -1, "Operation: %s", val_to_str(op, dcc_op_vals, "Unknown Op: %u")); dcc_optree = proto_item_add_subtree(ti, ett_dcc_op); switch(op) { case DCC_OP_NOP: D_SIGNATURE(); break; case DCC_OP_REPORT: D_TARGET(); for (i=0; i<=DCC_QUERY_MAX && tvb_bytes_exist(tvb, offset+sizeof(DCC_SIGNATURE),1); i++) { D_CHECKSUM(); } D_SIGNATURE(); break; case DCC_OP_QUERY_RESP: for (i=0; i<=DCC_QUERY_MAX && tvb_bytes_exist(tvb, offset+sizeof(DCC_SIGNATURE),1); i++) { D_TARGET(); } D_SIGNATURE(); break; case DCC_OP_ADMN: if ( is_response ) { int left_local = tvb_length_remaining(tvb, offset) - sizeof(DCC_SIGNATURE); if ( left_local == sizeof(DCC_ADMN_RESP_CLIENTS) ) { D_LABEL("Addr", 16); D_LABEL("Id", sizeof(DCC_CLNT_ID)); D_LABEL("Last Used", 4); D_LABEL("Requests", 4); } else { D_TEXT("Response Text", sizeof(DCC_SIGNATURE)); } D_SIGNATURE(); } else { int aop; D_DATE(); aop = tvb_get_guint8(tvb, offset+4); proto_tree_add_item(dcc_optree, hf_dcc_adminop, tvb, offset+4, 1, FALSE); if (check_col(pinfo->cinfo, COL_INFO)) { col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", val_to_str(tvb_get_guint8(tvb,offset+4), dcc_adminop_vals, "Unknown (%u)")); } if (aop == DCC_AOP_TRACE_ON || aop == DCC_AOP_TRACE_OFF ) { ti = proto_tree_add_item(dcc_optree, hf_dcc_trace, tvb, offset, 4, FALSE); dcc_tracetree = proto_item_add_subtree(ti, ett_dcc_trace); proto_tree_add_item(dcc_tracetree, hf_dcc_trace_admin, tvb, offset, 4, FALSE); proto_tree_add_item(dcc_tracetree, hf_dcc_trace_anon, tvb, offset, 4, FALSE); proto_tree_add_item(dcc_tracetree, hf_dcc_trace_client, tvb, offset, 4, FALSE); proto_tree_add_item(dcc_tracetree, hf_dcc_trace_rlim, tvb, offset, 4, FALSE); proto_tree_add_item(dcc_tracetree, hf_dcc_trace_query, tvb, offset, 4, FALSE); proto_tree_add_item(dcc_tracetree, hf_dcc_trace_ridc, tvb, offset, 4, FALSE); proto_tree_add_item(dcc_tracetree, hf_dcc_trace_flood, tvb, offset, 4, FALSE); } else if ( aop == DCC_AOP_FLOD ) { proto_tree_add_item(dcc_optree, hf_dcc_floodop, tvb, offset, 4, FALSE); if (check_col(pinfo->cinfo, COL_INFO)) { col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", val_to_str(tvb_get_ntohl(tvb,offset), dcc_floodop_vals, "Unknown (%u)")); } } else { proto_tree_add_item(dcc_optree, hf_dcc_adminval, tvb, offset, 4, FALSE); } offset += 4; offset += 1; /* admin op we did in reverse order */ D_LABEL("Pad", 3); D_SIGNATURE(); } break; case DCC_OP_OK: proto_tree_add_item(dcc_optree, hf_dcc_max_pkt_vers, tvb, offset, 1, FALSE); offset += 1; D_LABEL("Unused", 1); proto_tree_add_item(dcc_optree, hf_dcc_qdelay_ms, tvb, offset, 2, FALSE); offset += 2; proto_tree_add_item(dcc_optree, hf_dcc_brand, tvb, offset, sizeof(DCC_BRAND), FALSE); offset += sizeof(DCC_BRAND); D_SIGNATURE(); break; default: /* do nothing */ break; } } return TRUE; }
static int dissect_InitiatingMessageValue(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { return (dissector_try_uint(sbc_ap_proc_imsg_dissector_table, ProcedureCode, tvb, pinfo, tree)) ? tvb_length(tvb) : 0; }
/* * dissect_pgm - The dissector for Pragmatic General Multicast */ static void dissect_pgm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { guint16 pgmhdr_sport; guint16 pgmhdr_dport; guint8 pgmhdr_type; guint8 pgmhdr_opts; guint16 pgmhdr_cksum; guint16 pgmhdr_tsdulen; guint32 sqn; guint16 afi; guint plen = 0; proto_item *ti; const char *pktname; const char *pollstname; char *gsi; gboolean isdata = FALSE; guint pgmlen, reportedlen; col_set_str(pinfo->cinfo, COL_PROTOCOL, "PGM"); if (check_col(pinfo->cinfo, COL_INFO)) { col_clear(pinfo->cinfo, COL_INFO); if (tvb_reported_length_remaining(tvb, 0) < 18) { col_set_str(pinfo->cinfo, COL_INFO, "Packet too small"); return; } } pinfo->srcport = pgmhdr_sport = tvb_get_ntohs(tvb, 0); pinfo->destport = pgmhdr_dport = tvb_get_ntohs(tvb, 2); pgmhdr_type = tvb_get_guint8(tvb, 4); pktname = val_to_str(pgmhdr_type, type_vals, "Unknown (0x%02x)"); pgmhdr_opts = tvb_get_guint8(tvb, 5); pgmhdr_cksum = tvb_get_ntohs(tvb, 6); gsi = tvb_bytes_to_str(tvb, 8, 6); pgmhdr_tsdulen = tvb_get_ntohs(tvb, 14); sqn = tvb_get_ntohl(tvb, 16); switch(pgmhdr_type) { case PGM_SPM_PCKT: case PGM_NAK_PCKT: case PGM_NNAK_PCKT: case PGM_NCF_PCKT: case PGM_POLR_PCKT: case PGM_ACK_PCKT: if (check_col(pinfo->cinfo, COL_INFO)) { col_add_fstr(pinfo->cinfo, COL_INFO, "%-5s sqn 0x%x gsi %s", pktname, sqn, gsi); } break; case PGM_RDATA_PCKT: case PGM_ODATA_PCKT: if (check_col(pinfo->cinfo, COL_INFO)) { col_add_fstr(pinfo->cinfo, COL_INFO, "%-5s sqn 0x%x gsi %s tsdulen %d", pktname, sqn, gsi, pgmhdr_tsdulen); } isdata = TRUE; break; case PGM_POLL_PCKT: { guint16 poll_stype = tvb_get_ntohs(tvb, 22); pollstname = val_to_str(poll_stype, poll_subtype_vals, "Unknown (0x%02x)"); if (check_col(pinfo->cinfo, COL_INFO)) { col_add_fstr(pinfo->cinfo, COL_INFO, "%-5s sqn 0x%x gsi %s subtype %s", pktname, sqn, gsi, pollstname); } } break; default: return; } { proto_tree *pgm_tree = NULL; proto_tree *opt_tree = NULL; proto_tree *type_tree = NULL; proto_item *tf, *hidden_item; ptvcursor_t* cursor; ti = proto_tree_add_protocol_format(tree, proto_pgm, tvb, 0, -1, "Pragmatic General Multicast: Type %s" " Src Port %u, Dst Port %u, GSI %s", pktname, pgmhdr_sport, pgmhdr_dport, gsi); pgm_tree = proto_item_add_subtree(ti, ett_pgm); cursor = ptvcursor_new(pgm_tree, tvb, 0); hidden_item = proto_tree_add_item(pgm_tree, hf_pgm_port, tvb, 0, 2, ENC_BIG_ENDIAN); PROTO_ITEM_SET_HIDDEN(hidden_item); hidden_item = proto_tree_add_item(pgm_tree, hf_pgm_port, tvb, 2, 2, ENC_BIG_ENDIAN); PROTO_ITEM_SET_HIDDEN(hidden_item); ptvcursor_add(cursor, hf_pgm_main_sport, 2, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_main_dport, 2, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_main_type, 1, ENC_BIG_ENDIAN); tf = proto_tree_add_uint_format(pgm_tree, hf_pgm_main_opts, tvb, ptvcursor_current_offset(cursor), 1, pgmhdr_opts, "Options: %s (0x%x)", optsstr(pgmhdr_opts), pgmhdr_opts); opt_tree = proto_item_add_subtree(tf, ett_pgm_optbits); ptvcursor_set_tree(cursor, opt_tree); ptvcursor_add_no_advance(cursor, hf_pgm_main_opts_opt, 1, ENC_BIG_ENDIAN); ptvcursor_add_no_advance(cursor, hf_pgm_main_opts_netsig, 1, ENC_BIG_ENDIAN); ptvcursor_add_no_advance(cursor, hf_pgm_main_opts_varlen, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_main_opts_parity, 1, ENC_BIG_ENDIAN); ptvcursor_set_tree(cursor, pgm_tree); /* Checksum may be 0 (not available), but not for DATA packets */ if ((pgmhdr_type != PGM_RDATA_PCKT) && (pgmhdr_type != PGM_ODATA_PCKT) && (pgmhdr_cksum == 0)) { proto_tree_add_uint_format(pgm_tree, hf_pgm_main_cksum, tvb, ptvcursor_current_offset(cursor), 2, pgmhdr_cksum, "Checksum: not available"); } else { reportedlen = tvb_reported_length(tvb); pgmlen = tvb_length(tvb); if (pgm_check_checksum && pgmlen >= reportedlen) { vec_t cksum_vec[1]; guint16 computed_cksum; cksum_vec[0].ptr = tvb_get_ptr(tvb, 0, pgmlen); cksum_vec[0].len = pgmlen; computed_cksum = in_cksum(&cksum_vec[0], 1); if (computed_cksum == 0) { proto_tree_add_uint_format(pgm_tree, hf_pgm_main_cksum, tvb, ptvcursor_current_offset(cursor), 2, pgmhdr_cksum, "Checksum: 0x%04x [correct]", pgmhdr_cksum); } else { hidden_item = proto_tree_add_boolean(pgm_tree, hf_pgm_main_cksum_bad, tvb, ptvcursor_current_offset(cursor), 2, TRUE); PROTO_ITEM_SET_HIDDEN(hidden_item); proto_tree_add_uint_format(pgm_tree, hf_pgm_main_cksum, tvb, ptvcursor_current_offset(cursor), 2, pgmhdr_cksum, "Checksum: 0x%04x [incorrect, should be 0x%04x]", pgmhdr_cksum, in_cksum_shouldbe(pgmhdr_cksum, computed_cksum)); } } else { ptvcursor_add_no_advance(cursor, hf_pgm_main_cksum, 2, ENC_BIG_ENDIAN); } } ptvcursor_advance(cursor, 2); ptvcursor_add(cursor, hf_pgm_main_gsi, 6, ENC_NA); ptvcursor_add(cursor, hf_pgm_main_tsdulen, 2, ENC_BIG_ENDIAN); tf = proto_tree_add_text(pgm_tree, tvb, ptvcursor_current_offset(cursor), plen, "%s Packet", pktname); switch(pgmhdr_type) { case PGM_SPM_PCKT: type_tree = proto_item_add_subtree(tf, ett_pgm_spm); ptvcursor_set_tree(cursor, type_tree); ptvcursor_add(cursor, hf_pgm_spm_sqn, 4, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_spm_trail, 4, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_spm_lead, 4, ENC_BIG_ENDIAN); afi = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor)); ptvcursor_add(cursor, hf_pgm_spm_pathafi, 2, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_spm_res, 2, ENC_BIG_ENDIAN); switch (afi) { case AFNUM_INET: ptvcursor_add(cursor, hf_pgm_spm_path, 4, ENC_BIG_ENDIAN); break; case AFNUM_INET6: ptvcursor_add(cursor, hf_pgm_spm_path6, 16, ENC_NA); break; default: proto_tree_add_text(type_tree, tvb, ptvcursor_current_offset(cursor), -1, "Can't handle this address format"); return; } break; case PGM_RDATA_PCKT: case PGM_ODATA_PCKT: type_tree = proto_item_add_subtree(tf, ett_pgm_data); ptvcursor_set_tree(cursor, type_tree); ptvcursor_add(cursor, hf_pgm_spm_sqn, 4, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_spm_trail, 4, ENC_BIG_ENDIAN); break; case PGM_NAK_PCKT: case PGM_NNAK_PCKT: case PGM_NCF_PCKT: type_tree = proto_item_add_subtree(tf, ett_pgm_nak); ptvcursor_set_tree(cursor, type_tree); ptvcursor_add(cursor, hf_pgm_nak_sqn, 4, ENC_BIG_ENDIAN); afi = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor)); ptvcursor_add(cursor, hf_pgm_nak_srcafi, 2, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_nak_srcres, 2, ENC_BIG_ENDIAN); switch (afi) { case AFNUM_INET: ptvcursor_add(cursor, hf_pgm_nak_src, 4, ENC_BIG_ENDIAN); break; case AFNUM_INET6: ptvcursor_add(cursor, hf_pgm_nak_src6, 16, ENC_NA); break; default: proto_tree_add_text(type_tree, tvb, ptvcursor_current_offset(cursor), -1, "Can't handle this address format"); break; } afi = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor)); ptvcursor_add(cursor, hf_pgm_nak_grpafi, 2, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_nak_grpres, 2, ENC_BIG_ENDIAN); switch (afi) { case AFNUM_INET: ptvcursor_add(cursor, hf_pgm_nak_grp, 4, ENC_BIG_ENDIAN); break; case AFNUM_INET6: ptvcursor_add(cursor, hf_pgm_nak_grp6, 16, ENC_NA); break; default: proto_tree_add_text(type_tree, tvb, ptvcursor_current_offset(cursor), -1, "Can't handle this address format"); return; } break; case PGM_POLL_PCKT: type_tree = proto_item_add_subtree(tf, ett_pgm_poll); ptvcursor_set_tree(cursor, type_tree); ptvcursor_add(cursor, hf_pgm_poll_sqn, 4, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_poll_round, 2, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_poll_subtype, 2, ENC_BIG_ENDIAN); afi = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor)); ptvcursor_add(cursor, hf_pgm_poll_pathafi, 2, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_poll_res, 2, ENC_BIG_ENDIAN); switch (afi) { case AFNUM_INET: ptvcursor_add(cursor, hf_pgm_poll_path, 4, ENC_BIG_ENDIAN); break; case AFNUM_INET6: ptvcursor_add(cursor, hf_pgm_poll_path6, 16, ENC_NA); break; default: proto_tree_add_text(type_tree, tvb, ptvcursor_current_offset(cursor), -1, "Can't handle this address format"); break; } ptvcursor_add(cursor, hf_pgm_poll_backoff_ivl, 4, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_poll_rand_str, 4, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_poll_matching_bmask, 4, ENC_BIG_ENDIAN); break; case PGM_POLR_PCKT: type_tree = proto_item_add_subtree(tf, ett_pgm_polr); ptvcursor_set_tree(cursor, type_tree); ptvcursor_add(cursor, hf_pgm_polr_sqn, 4, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_polr_round, 2, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_polr_res, 2, ENC_BIG_ENDIAN); break; case PGM_ACK_PCKT: type_tree = proto_item_add_subtree(tf, ett_pgm_ack); ptvcursor_set_tree(cursor, type_tree); ptvcursor_add(cursor, hf_pgm_ack_sqn, 4, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_ack_bitmap, 4, ENC_BIG_ENDIAN); break; } if (pgmhdr_opts & PGM_OPT) dissect_pgmopts(cursor, pktname); if (isdata) decode_pgm_ports(tvb, ptvcursor_current_offset(cursor), pinfo, tree, pgmhdr_sport, pgmhdr_dport); } }
static void dissect_gmr1_dtap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { guint32 len, offset; gmr1_msg_func_t msg_func; const gchar *msg_str; gint ett_tree; int hf_idx; proto_item *dtap_item = NULL/*, *pd_item = NULL*/; proto_tree *dtap_tree = NULL/*, *pd_tree = NULL*/; guint32 oct[2]; guint8 pd; /* Scan init */ len = tvb_length(tvb); offset = 0; /* Protocol descriptor */ oct[0] = tvb_get_guint8(tvb, offset++); if ((oct[0] & GMR1_PD_EXT_MSK) == GMR1_PD_EXT_VAL) pd = oct[0] & 0xff; else pd = oct[0] & 0x0f; /* HACK: Quick delegation hack to GSM */ if (pd != GMR1_PD_RR) { call_dissector(gsm_dtap_handle, tvb, pinfo, tree); return; } /* Fill up some info */ col_append_str(pinfo->cinfo, COL_INFO, " (DTAP) "); col_append_fstr(pinfo->cinfo, COL_INFO, "(%s) ", val_to_str(pd, gmr1_pd_short_vals, "Unknown (%u)")); /* Get message parameters */ oct[1] = tvb_get_guint8(tvb, offset); gmr1_get_msg_params((gmr1_pd_e)pd, oct[1], &msg_str, &ett_tree, &hf_idx, &msg_func); /* Create protocol tree */ if (msg_str == NULL) { dtap_item = proto_tree_add_protocol_format( tree, proto_gmr1_dtap, tvb, 0, len, "GMR-1 DTAP - Message Type (0x%02x)", oct[1]); dtap_tree = proto_item_add_subtree(dtap_item, ett_gmr1_dtap); col_append_fstr(pinfo->cinfo, COL_INFO, "Message Type (0x%02x) ", oct[1]); } else { dtap_item = proto_tree_add_protocol_format( tree, proto_gmr1_dtap, tvb, 0, -1, "GMR-1 DTAP - %s", msg_str); dtap_tree = proto_item_add_subtree(dtap_item, ett_gmr1_dtap); col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", msg_str); } /* Start over */ offset = 0; /* Protocol discriminator item */ /*pd_item =*/ proto_tree_add_text( dtap_tree, tvb, 1, 1, "Protocol Discriminator: %s", val_to_str(pd, gmr1_pd_vals, "Unknown (%u)") ); /*pd_tree = proto_item_add_subtree(pd_item, ett_gmr1_pd);*/ /* Move on */ offset++; /* Message type - [1] 11.4 */ proto_tree_add_uint_format( dtap_tree, hf_idx, tvb, offset, 1, oct[1], "Message Type: %s", msg_str ? msg_str : "(Unknown)" ); offset++; /* Decode elements */ if (msg_func) { (*msg_func)(tvb, dtap_tree, pinfo, offset, len - offset); } else { proto_tree_add_text(dtap_tree, tvb, offset, len - offset, "Message Elements"); } /* Done ! */ return; }
static int dissect_skype_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_item *ti; proto_tree *skype_tree = NULL; guint32 offset = 0; guint32 packet_length; guint8 packet_type, packet_unk; conversation_t *conversation = NULL; skype_udp_conv_info_t *skype_udp_info; /* look up the conversation */ conversation = find_or_create_conversation(pinfo); /* if conversation found get the data pointer that you stored */ skype_udp_info = conversation_get_proto_data(conversation, proto_skype); if (!skype_udp_info) { /* new conversation create local data structure */ skype_udp_info = se_alloc(sizeof(skype_udp_conv_info_t)); skype_udp_info->global_src_ip = 0; skype_udp_info->global_dst_ip = 0; conversation_add_proto_data(conversation, proto_skype, skype_udp_info); } /* at this point the conversation data is ready */ packet_type = tvb_get_guint8(tvb, 2) & SKYPE_SOM_TYPE_MASK; packet_unk = (tvb_get_guint8(tvb, 2) & SKYPE_SOM_UNK_MASK) >> 4; packet_length = tvb_length(tvb); col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_SHORT_NAME); col_add_str(pinfo->cinfo, COL_INFO, val_to_str(packet_type, skype_type_vals, "Type 0x%1x")); if (packet_unk) { col_append_fstr(pinfo->cinfo, COL_INFO, " Unk: %1x", packet_unk); } if (tree) { /* Start of message dissection */ ti = proto_tree_add_item(tree, proto_skype, tvb, offset, -1, ENC_NA); skype_tree = proto_item_add_subtree(ti, ett_skype); proto_tree_add_item(skype_tree, hf_skype_som_id, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(skype_tree, hf_skype_som_unk, tvb, offset, 1, ENC_NA); proto_tree_add_item(skype_tree, hf_skype_som_type, tvb, offset, 1, ENC_NA); offset += 1; /* Body dissection */ switch (packet_type) { case SKYPE_TYPE_UNKNOWN_0: proto_tree_add_item(skype_tree, hf_skype_unknown_0_unk1, tvb, offset, -1, ENC_NA); offset = packet_length; break; case SKYPE_TYPE_PAYLOAD: proto_tree_add_item(skype_tree, hf_skype_payload_iv, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(skype_tree, hf_skype_payload_crc, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(skype_tree, hf_skype_payload_enc_data, tvb, offset, -1, ENC_NA); offset = packet_length; break; case SKYPE_TYPE_FFR: proto_tree_add_item(skype_tree, hf_skype_ffr_num, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item(skype_tree, hf_skype_ffr_unk1, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(skype_tree, hf_skype_ffr_iv, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(skype_tree, hf_skype_ffr_crc, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(skype_tree, hf_skype_ffr_enc_data, tvb, offset, -1, ENC_NA); offset = packet_length; break; case SKYPE_TYPE_NAT_INFO: proto_tree_add_item(skype_tree, hf_skype_natinfo_srcip, tvb, offset, 4, ENC_BIG_ENDIAN); skype_udp_info->global_src_ip = tvb_get_ipv4(tvb, offset); offset += 4; proto_tree_add_item(skype_tree, hf_skype_natinfo_dstip, tvb, offset, 4, ENC_BIG_ENDIAN); skype_udp_info->global_dst_ip = tvb_get_ipv4(tvb, offset); offset += 4; break; case SKYPE_TYPE_NAT_REPEAT: proto_tree_add_item(skype_tree, hf_skype_natrequest_srcip, tvb, offset, 4, ENC_BIG_ENDIAN); skype_udp_info->global_src_ip = tvb_get_ipv4(tvb, offset); offset += 4; proto_tree_add_item(skype_tree, hf_skype_natrequest_dstip, tvb, offset, 4, ENC_BIG_ENDIAN); skype_udp_info->global_dst_ip = tvb_get_ipv4(tvb, offset); offset += 4; break; case SKYPE_TYPE_AUDIO: proto_tree_add_item(skype_tree, hf_skype_audio_unk1, tvb, offset, -1, ENC_NA); offset = packet_length; break; case SKYPE_TYPE_UNKNOWN_F: proto_tree_add_item(skype_tree, hf_skype_unknown_f_unk1, tvb, offset, -1, ENC_NA); offset = packet_length; break; default: proto_tree_add_item(skype_tree, hf_skype_unknown_packet, tvb, offset, -1, ENC_NA); offset = packet_length; break; } } return offset; }
static void dissect_pop(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { struct pop_proto_data *frame_data_p; gboolean is_request; gboolean is_continuation; proto_tree *pop_tree, *reqresp_tree; proto_item *ti; gint offset = 0; const guchar *line; gint next_offset; int linelen; int tokenlen; const guchar *next_token; fragment_data *frag_msg = NULL; tvbuff_t *next_tvb = NULL; conversation_t *conversation = NULL; struct pop_data_val *data_val = NULL; gint length_remaining; col_set_str(pinfo->cinfo, COL_PROTOCOL, "POP"); /* * Find the end of the first line. * * Note that "tvb_find_line_end()" will return a value that is * not longer than what's in the buffer, so the "tvb_get_ptr()" * call won't throw an exception. */ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); line = tvb_get_ptr(tvb, offset, linelen); if (pinfo->match_uint == pinfo->destport) { is_request = TRUE; is_continuation = FALSE; } else { is_request = FALSE; is_continuation = response_is_continuation(line); } frame_data_p = p_get_proto_data(pinfo->fd, proto_pop); if (!frame_data_p) { conversation = find_or_create_conversation(pinfo); data_val = conversation_get_proto_data(conversation, proto_pop); if (!data_val) { /* * No - create one and attach it. */ data_val = se_alloc0(sizeof(struct pop_data_val)); conversation_add_proto_data(conversation, proto_pop, data_val); } } if (check_col(pinfo->cinfo, COL_INFO)) { /* * Put the first line from the buffer into the summary * if it's a POP request or reply (but leave out the * line terminator). * Otherwise, just call it a continuation. */ if (is_continuation) { length_remaining = tvb_length_remaining(tvb, offset); col_add_fstr(pinfo->cinfo, COL_INFO, "S: DATA fragment, %d byte%s", length_remaining, plurality (length_remaining, "", "s")); } else col_add_fstr(pinfo->cinfo, COL_INFO, "%s: %s", is_request ? "C" : "S", format_text(line, linelen)); } ti = proto_tree_add_item(tree, proto_pop, tvb, offset, -1, ENC_NA); pop_tree = proto_item_add_subtree(ti, ett_pop); if (is_continuation) { if (pop_data_desegment) { if (!frame_data_p) { data_val->msg_read_len += tvb_length(tvb); frame_data_p = se_alloc(sizeof(struct pop_proto_data)); frame_data_p->conversation_id = conversation->index; frame_data_p->more_frags = data_val->msg_read_len < data_val->msg_tot_len; p_add_proto_data(pinfo->fd, proto_pop, frame_data_p); } frag_msg = fragment_add_seq_next(tvb, 0, pinfo, frame_data_p->conversation_id, pop_data_segment_table, pop_data_reassembled_table, tvb_length(tvb), frame_data_p->more_frags); next_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled DATA", frag_msg, &pop_data_frag_items, NULL, pop_tree); if (next_tvb) { if (imf_handle) call_dissector(imf_handle, next_tvb, pinfo, tree); if (data_val) { /* we have read everything - reset */ data_val->msg_read_len = 0; data_val->msg_tot_len = 0; } pinfo->fragmented = FALSE; } else { pinfo->fragmented = TRUE; } } else { /* * Put the whole packet into the tree as data. */ call_dissector(data_handle,tvb, pinfo, pop_tree); } return; } /* * Put the line into the protocol tree. */ ti = proto_tree_add_string_format(pop_tree, (is_request) ? hf_pop_request : hf_pop_response, tvb, offset, next_offset - offset, "", "%s", tvb_format_text(tvb, offset, next_offset - offset)); reqresp_tree = proto_item_add_subtree(ti, ett_pop_reqresp); /* * Extract the first token, and, if there is a first * token, add it as the request or reply code. */ tokenlen = get_token_len(line, line + linelen, &next_token); if (tokenlen != 0) { proto_tree_add_item(reqresp_tree, (is_request) ? hf_pop_request_command : hf_pop_response_indicator, tvb, offset, tokenlen, ENC_ASCII|ENC_NA); if (data_val) { if (is_request) { /* see if this is RETR or TOP command */ if (g_ascii_strncasecmp(line, "RETR", 4) == 0 || g_ascii_strncasecmp(line, "TOP", 3) == 0) /* the next response will tell us how many bytes */ data_val->msg_request = TRUE; } else { if (data_val->msg_request) { /* this is a response to a RETR or TOP command */ if (g_ascii_strncasecmp(line, "+OK ", 4) == 0) { /* the message will be sent - work out how many bytes */ data_val->msg_read_len = 0; data_val->msg_tot_len = atoi(line + 4); } data_val->msg_request = FALSE; } } } offset += (gint) (next_token - line); linelen -= (int) (next_token - line); } if (tree) { /* * Add the rest of the first line as request or * reply param/description. */ if (linelen != 0) { proto_tree_add_item(reqresp_tree, (is_request) ? hf_pop_request_parameter : hf_pop_response_description, tvb, offset, linelen, ENC_ASCII|ENC_NA); } offset = next_offset; /* * Show the rest of the request or response as text, * a line at a time. */ while (tvb_offset_exists(tvb, offset)) { /* * Find the end of the line. */ tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); /* * Put this line. */ proto_tree_add_string_format(pop_tree, (is_request) ? hf_pop_request_data : hf_pop_response_data, tvb, offset, next_offset - offset, "", "%s", tvb_format_text(tvb, offset, next_offset - offset)); offset = next_offset; } } }
/* * For PIM v2, see RFC 4601, RFC 3973 and draft-ietf-pim-sm-v2-new-03 * (when PIM is run over IPv6, the rules for computing the PIM checksum * from the draft in question, not from RFC 2362, should be used). */ static void dissect_pim(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { int offset = 0; guint8 pim_typever; guint length, pim_length; guint16 pim_cksum, computed_cksum; vec_t cksum_vec[4]; guint32 phdr[2]; const char *typestr; proto_tree *pim_tree = NULL; proto_item *ti; proto_tree *pimopt_tree = NULL; proto_item *tiopt; col_set_str(pinfo->cinfo, COL_PROTOCOL, "PIM"); col_clear(pinfo->cinfo, COL_INFO); pim_typever = tvb_get_guint8(tvb, 0); switch (PIM_VER(pim_typever)) { case 2: typestr = val_to_str(PIM_TYPE(pim_typever), type2vals, "Unknown (%u)"); break; case 1: /* PIMv1 - we should never see this */ default: typestr = "Unknown"; break; } if (check_col(pinfo->cinfo, COL_PROTOCOL)) { col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "PIMv%d", PIM_VER(pim_typever)); } if (check_col(pinfo->cinfo, COL_INFO)) col_add_str(pinfo->cinfo, COL_INFO, typestr); ti = proto_tree_add_item(tree, proto_pim, tvb, offset, -1, FALSE); pim_tree = proto_item_add_subtree(ti, ett_pim); proto_tree_add_item(pim_tree, hf_pim_version, tvb, offset, 1, FALSE); proto_tree_add_item(pim_tree, hf_pim_type, tvb, offset, 1, FALSE); proto_tree_add_item(pim_tree, hf_pim_res_bytes, tvb, offset + 1, 1, FALSE); pim_cksum = tvb_get_ntohs(tvb, offset + 2); length = tvb_length(tvb); if (PIM_VER(pim_typever) == 2) { /* * Well, it's PIM v2, so we can check whether this is a Register * message, and thus can figure out how much to checksum and * whether to make the columns read-only. */ if (PIM_TYPE(pim_typever) == 1) { /* * Register message - the PIM header is 8 bytes long. * Also set the columns non-writable. Otherwise the IPv4 or * IPv6 dissector for the encapsulated packet that caused * this register will overwrite the PIM info in the columns. */ pim_length = 8; col_set_writable(pinfo->cinfo, FALSE); } else { /* * Other message - checksum the entire packet. */ pim_length = tvb_reported_length(tvb); } } else { /* * We don't know what type of message this is, so say that * the length is 0, to force it not to be checksummed. */ pim_length = 0; } if (!pinfo->fragmented && length >= pim_length) { /* * The packet isn't part of a fragmented datagram and isn't * truncated, so we can checksum it. */ switch (pinfo->src.type) { case AT_IPv4: cksum_vec[0].ptr = tvb_get_ptr(tvb, 0, pim_length); cksum_vec[0].len = pim_length; computed_cksum = in_cksum(&cksum_vec[0], 1); break; case AT_IPv6: /* Set up the fields of the pseudo-header. */ cksum_vec[0].ptr = pinfo->src.data; cksum_vec[0].len = pinfo->src.len; cksum_vec[1].ptr = pinfo->dst.data; cksum_vec[1].len = pinfo->dst.len; cksum_vec[2].ptr = (const guint8 *)&phdr; phdr[0] = g_htonl(pim_length); phdr[1] = g_htonl(IP_PROTO_PIM); cksum_vec[2].len = 8; cksum_vec[3].ptr = tvb_get_ptr(tvb, 0, pim_length); cksum_vec[3].len = pim_length; computed_cksum = in_cksum(&cksum_vec[0], 4); break; default: /* PIM is available for IPv4 and IPv6 right now */ computed_cksum = 0; /* squelch GCC complaints */ DISSECTOR_ASSERT_NOT_REACHED(); break; } if (computed_cksum == 0) { proto_tree_add_uint_format(pim_tree, hf_pim_cksum, tvb, offset + 2, 2, pim_cksum, "Checksum: 0x%04x [correct]", pim_cksum); } else { proto_tree_add_uint_format(pim_tree, hf_pim_cksum, tvb, offset + 2, 2, pim_cksum, "Checksum: 0x%04x [incorrect, should be 0x%04x]", pim_cksum, in_cksum_shouldbe(pim_cksum, computed_cksum)); } } else { proto_tree_add_uint(pim_tree, hf_pim_cksum, tvb, offset + 2, 2, pim_cksum); } offset += 4; if (tvb_reported_length_remaining(tvb, offset) > 0) { tiopt = proto_tree_add_text(pim_tree, tvb, offset, -1, "PIM options"); pimopt_tree = proto_item_add_subtree(tiopt, ett_pim_opts); } else goto done; if (PIM_VER(pim_typever) != 2) goto done; /* version 2 decoder */ switch (PIM_TYPE(pim_typever)) { case 0: /*hello*/ { int opt_count = 0; while (tvb_reported_length_remaining(tvb, offset) >= 2) { guint16 hello_opt, opt_len; guint16 opt_value; proto_item *opt_item; proto_tree *opt_tree; opt_count++; hello_opt = tvb_get_ntohs(tvb, offset); opt_len = tvb_get_ntohs(tvb, offset + 2); opt_item = proto_tree_add_text(pimopt_tree, tvb, offset, 4 + opt_len, "Option %u: %s", hello_opt, val_to_str(hello_opt, pim_opt_vals, "Unknown: %u")); opt_tree = proto_item_add_subtree(opt_item, ett_pim_opt); proto_tree_add_item(opt_tree, hf_pim_optiontype, tvb, offset, 2, FALSE); proto_tree_add_item(opt_tree, hf_pim_optionlength, tvb, offset + 2, 2, FALSE); switch(hello_opt) { case 1: /* Hello Hold Time Option */ opt_value = tvb_get_ntohs(tvb, offset + 4); proto_tree_add_uint_format(opt_tree, hf_pim_holdtime, tvb, offset + 4, opt_len, opt_value, "Holdtime: %us %s", opt_value, opt_value == 0 ? "(goodbye)" : opt_value == 0xffff ? "(infinity)": ""); proto_item_append_text(opt_item, ": %us %s", opt_value, opt_value == 0 ? "(goodbye)" : opt_value == 0xffff ? "(infinity)": ""); break; case 2: /* LAN Prune Delay Option */ proto_tree_add_item(opt_tree, hf_pim_t, tvb, offset + 4, 1, FALSE); proto_tree_add_item(opt_tree, hf_pim_propagation_delay, tvb, offset + 4, 2, FALSE); proto_tree_add_item(opt_tree, hf_pim_override_interval, tvb, offset + 6, 2, FALSE); proto_item_append_text(opt_item, ": T = %u, Propagation Delay = %ums, Override Interval = %ums", tvb_get_guint8(tvb, offset + 4) & 0x80 ? 1 : 0, tvb_get_ntohs(tvb, offset + 4) & 0x7fff, tvb_get_ntohs(tvb, offset + 6)); break; case 19: /* DR priority */ proto_tree_add_item(opt_tree, hf_pim_dr_priority, tvb, offset + 4, 4, FALSE); proto_item_append_text(opt_item, ": %u", tvb_get_ntohl(tvb, offset + 4)); break; case 20: /* Generation ID */ proto_tree_add_item(opt_tree, hf_pim_generation_id, tvb, offset + 4, 4, FALSE); proto_item_append_text(opt_item, ": %u", tvb_get_ntohl(tvb, offset + 4)); break; case 21: /* State Refresh Capable Option */ proto_tree_add_item(opt_tree, hf_pim_state_refresh_version, tvb, offset + 4, 1, FALSE); proto_tree_add_item(opt_tree, hf_pim_state_refresh_interval, tvb, offset + 5, 1, FALSE); proto_tree_add_item(opt_tree, hf_pim_state_refresh_reserved, tvb, offset + 6, 2, FALSE); proto_item_append_text(opt_item, ": Version = %u, Interval = %us", tvb_get_guint8(tvb, offset + 4), tvb_get_guint8(tvb, offset + 5)); break; case 24: /* address list */ case 65001: /* address list (old implementations) */ { int i; proto_tree *sub_tree = NULL; proto_item *addrlist_option; addrlist_option = proto_tree_add_text(opt_tree, tvb, offset, 4 + opt_len, "%sAddress List (%u)", hello_opt == 65001 ? "old " : "", hello_opt); sub_tree = proto_item_add_subtree(addrlist_option, ett_pim_opt); for (i = offset + 4; i < offset + 4 + opt_len; ) { int advance; const char *s; s = dissect_pim_addr(tvb, i, pimv2_unicast, &advance); if (s == NULL) break; proto_tree_add_text(sub_tree, tvb, offset, advance, "Address: %s", s); i += advance; } break; } default: if (opt_len) proto_tree_add_item(opt_tree, hf_pim_optionvalue, tvb, offset + 4, opt_len, FALSE); break; } offset += 4 + opt_len; } proto_item_append_text(tiopt, ": %u", opt_count); break; } case 1: /* register */ { guint32 flags; guint8 v_hl; tvbuff_t *next_tvb; proto_tree *flag_tree = NULL; proto_item *tiflag; flags = tvb_get_ntohl(tvb, offset); tiflag = proto_tree_add_text(pimopt_tree, tvb, offset, 4, "Flags: 0x%08x", flags); flag_tree = proto_item_add_subtree(tiflag, ett_pim); proto_tree_add_text(flag_tree, tvb, offset, 1, "%s", decode_boolean_bitfield(flags, 0x80000000, 32, "Border", "Not border")); proto_tree_add_text(flag_tree, tvb, offset, 1, "%s", decode_boolean_bitfield(flags, 0x40000000, 32, "Null-Register", "Not Null-Register")); offset += 4; /* * The rest of the packet is a multicast data packet. */ next_tvb = tvb_new_subset_remaining(tvb, offset); /* * It's an IP packet - determine whether it's IPv4 or IPv6. */ v_hl = tvb_get_guint8(tvb, offset); switch((v_hl & 0xf0) >> 4) { case 0: /* Null-Register dummy header. * Has the same address family as the encapsulating PIM packet, * e.g. an IPv6 data packet is encapsulated in IPv6 PIM packet. */ if (pinfo->src.type == AT_IPv4) { proto_tree_add_text(pimopt_tree, tvb, offset, -1, "IPv4 dummy header"); proto_tree_add_text(pimopt_tree, tvb, offset + 12, 4, "Source: %s", tvb_ip_to_str(tvb, offset + 12)); proto_tree_add_text(pimopt_tree, tvb, offset + 16, 4, "Group: %s", tvb_ip_to_str(tvb, offset + 16)); } else if (pinfo->src.type == AT_IPv6) { proto_tree_add_text(pimopt_tree, tvb, offset, -1, "IPv6 dummy header"); proto_tree_add_text(pimopt_tree, tvb, offset + 8, 16, "Source: %s", tvb_ip6_to_str(tvb, offset + 8)); proto_tree_add_text(pimopt_tree, tvb, offset + 8 + 16, 16, "Group: %s", tvb_ip6_to_str(tvb, offset + 8 + 16)); } else proto_tree_add_text(pimopt_tree, tvb, offset, -1, "Dummy header for an unknown protocol"); break; case 4: /* IPv4 */ #if 0 call_dissector(ip_handle, next_tvb, pinfo, tree); #else call_dissector(ip_handle, next_tvb, pinfo, pimopt_tree); #endif break; case 6: /* IPv6 */ #if 0 call_dissector(ipv6_handle, next_tvb, pinfo, tree); #else call_dissector(ipv6_handle, next_tvb, pinfo, pimopt_tree); #endif break; default: proto_tree_add_text(pimopt_tree, tvb, offset, -1, "Unknown IP version %d", (v_hl & 0xf0) >> 4); break; } break; } case 2: /* register-stop */ { int advance; const char *s; s = dissect_pim_addr(tvb, offset, pimv2_group, &advance); if (s == NULL) break; proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Group: %s", s); offset += advance; s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance); if (s == NULL) break; proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Source: %s", s); break; } case 3: /* join/prune */ case 6: /* graft */ case 7: /* graft-ack */ { int advance; int off; const char *s; int ngroup, i, njoin, nprune, j; guint16 holdtime; proto_tree *grouptree = NULL; proto_item *tigroup; proto_tree *subtree = NULL; proto_item *tisub; s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance); if (s == NULL) break; proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Upstream-neighbor: %s", s); offset += advance; proto_tree_add_item(pimopt_tree, hf_pim_res_bytes, tvb, offset, 1, FALSE); offset += 1; /* skip reserved field */ ngroup = tvb_get_guint8(tvb, offset); proto_tree_add_item(pimopt_tree, hf_pim_numgroups, tvb, offset, 1, FALSE); offset += 1; holdtime = tvb_get_ntohs(tvb, offset); proto_tree_add_uint_format(pimopt_tree, hf_pim_holdtime, tvb, offset, 2, holdtime, "Holdtime: %us %s", holdtime, holdtime == 0xffff ? "(infinity)": ""); offset += 2; for (i = 0; i < ngroup; i++) { s = dissect_pim_addr(tvb, offset, pimv2_group, &advance); if (s == NULL) goto breakbreak3; tigroup = proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Group %d: %s", i, s); grouptree = proto_item_add_subtree(tigroup, ett_pim); offset += advance; njoin = tvb_get_ntohs(tvb, offset); nprune = tvb_get_ntohs(tvb, offset + 2); tisub = proto_tree_add_item(grouptree, hf_pim_numjoins, tvb, offset, 2, FALSE); subtree = proto_item_add_subtree(tisub, ett_pim); off = offset + 4; for (j = 0; j < njoin; j++) { s = dissect_pim_addr(tvb, off, pimv2_source, &advance); if (s == NULL) goto breakbreak3; proto_tree_add_text(subtree, tvb, off, advance, "IP address: %s", s); off += advance; } tisub = proto_tree_add_item(grouptree, hf_pim_numprunes, tvb, offset + 2, 2, FALSE); subtree = proto_item_add_subtree(tisub, ett_pim); for (j = 0; j < nprune; j++) { s = dissect_pim_addr(tvb, off, pimv2_source, &advance); if (s == NULL) goto breakbreak3; proto_tree_add_text(subtree, tvb, off, advance, "IP address: %s", s); off += advance; } offset = off; } breakbreak3: break; } case 4: /* bootstrap */ { const char *s; int advance; int i, j; int frpcnt; guint16 holdtime; proto_tree *grouptree = NULL; proto_item *tigroup; proto_tree_add_text(pimopt_tree, tvb, offset, 2, "Fragment tag: 0x%04x", tvb_get_ntohs(tvb, offset)); offset += 2; proto_tree_add_text(pimopt_tree, tvb, offset, 1, "Hash mask len: %u", tvb_get_guint8(tvb, offset)); offset += 1; proto_tree_add_text(pimopt_tree, tvb, offset, 1, "BSR priority: %u", tvb_get_guint8(tvb, offset)); offset += 1; s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance); if (s == NULL) break; proto_tree_add_text(pimopt_tree, tvb, offset, advance, "BSR: %s", s); offset += advance; for (i = 0; tvb_reported_length_remaining(tvb, offset) > 0; i++) { s = dissect_pim_addr(tvb, offset, pimv2_group, &advance); if (s == NULL) goto breakbreak4; tigroup = proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Group %d: %s", i, s); grouptree = proto_item_add_subtree(tigroup, ett_pim); offset += advance; proto_tree_add_text(grouptree, tvb, offset, 1, "RP count: %u", tvb_get_guint8(tvb, offset)); offset += 1; frpcnt = tvb_get_guint8(tvb, offset); proto_tree_add_text(grouptree, tvb, offset, 1, "FRP count: %u", frpcnt); offset += 3; for (j = 0; j < frpcnt; j++) { s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance); if (s == NULL) goto breakbreak4; proto_tree_add_text(grouptree, tvb, offset, advance, "RP %d: %s", j, s); offset += advance; holdtime = tvb_get_ntohs(tvb, offset); proto_tree_add_uint_format(grouptree, hf_pim_holdtime, tvb, offset, 2, holdtime, "Holdtime: %us %s", holdtime, holdtime == 0xffff ? "(infinity)": ""); offset += 2; proto_tree_add_text(grouptree, tvb, offset, 1, "Priority: %u", tvb_get_guint8(tvb, offset)); offset += 2; /* also skips reserved field */ } } breakbreak4: break; } case 5: /* assert */ { const char *s; int advance; guint32 pref; s = dissect_pim_addr(tvb, offset, pimv2_group, &advance); if (s == NULL) break; proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Group: %s", s); offset += advance; s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance); if (s == NULL) break; proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Source: %s", s); offset += advance; proto_tree_add_item(pimopt_tree, hf_pim_rpt, tvb, offset, 1, FALSE); pref = tvb_get_ntohl(tvb, offset) & 0x7fffffff; proto_tree_add_uint_format(pimopt_tree, hf_pim_metric_pref, tvb, offset, 4, pref, "Metric Preference: %u", pref); offset += 4; proto_tree_add_item(pimopt_tree, hf_pim_metric, tvb, offset, 4, FALSE); offset += 4; break; } case 8: /* Candidate-RP-Advertisement */ { const char *s; int advance; int pfxcnt; guint16 holdtime; int i; pfxcnt = tvb_get_guint8(tvb, offset); proto_tree_add_text(pimopt_tree, tvb, offset, 1, "Prefix-count: %u", pfxcnt); offset += 1; proto_tree_add_text(pimopt_tree, tvb, offset, 1, "Priority: %u", tvb_get_guint8(tvb, offset)); offset += 1; holdtime = tvb_get_ntohs(tvb, offset); proto_tree_add_uint_format(pimopt_tree, hf_pim_holdtime, tvb, offset, 2, holdtime, "Holdtime: %us %s", holdtime, holdtime == 0xffff ? "(infinity)": ""); offset += 2; s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance); if (s == NULL) break; proto_tree_add_text(pimopt_tree, tvb, offset, advance, "RP: %s", s); offset += advance; for (i = 0; i < pfxcnt; i++) { s = dissect_pim_addr(tvb, offset, pimv2_group, &advance); if (s == NULL) goto breakbreak8; proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Group %d: %s", i, s); offset += advance; } breakbreak8: break; } case 9: /* State-Refresh */ { const char *s; int advance; guint32 pref; s = dissect_pim_addr(tvb, offset, pimv2_group, &advance); if (s == NULL) break; proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Group: %s", s); offset += advance; s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance); if (s == NULL) break; proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Source: %s", s); offset += advance; s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance); if (s == NULL) break; proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Originator: %s", s); offset += advance; proto_tree_add_item(pimopt_tree, hf_pim_rpt, tvb, offset, 1, FALSE); pref = tvb_get_ntohl(tvb, offset) & 0x7fffffff; proto_tree_add_uint_format(pimopt_tree, hf_pim_metric_pref, tvb, offset, 4, pref, "Metric Preference: %u", pref); offset += 4; proto_tree_add_item(pimopt_tree, hf_pim_metric, tvb, offset, 4, FALSE); offset += 4; proto_tree_add_text(pimopt_tree, tvb, offset, 1, "Masklen: %u", tvb_get_guint8(tvb, offset)); offset += 1; proto_tree_add_text(pimopt_tree, tvb, offset, 1, "TTL: %u", tvb_get_guint8(tvb, offset)); offset += 1; proto_tree_add_text(pimopt_tree, tvb, offset, 1, "Prune indicator %s", decode_boolean_bitfield(tvb_get_guint8(tvb, offset), 0x80, 8, "set", "clear")); proto_tree_add_text(pimopt_tree, tvb, offset, 1, "Prune now %s", decode_boolean_bitfield(tvb_get_guint8(tvb, offset), 0x40, 8, "set", "clear")); proto_tree_add_text(pimopt_tree, tvb, offset, 1, "Assert override %s", decode_boolean_bitfield(tvb_get_guint8(tvb, offset), 0x20, 8, "set", "clear")); offset += 1; proto_tree_add_text(pimopt_tree, tvb, offset, 1, "Interval: %u", tvb_get_guint8(tvb, offset)); offset += 1; break; } default: break; } done:; }
static void dissect_gsm_um(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *gsm_um_tree = NULL; proto_item *ti; col_set_str(pinfo->cinfo, COL_PROTOCOL, "GSM Um"); if (pinfo->pseudo_header->gsm_um.uplink) { col_set_str(pinfo->cinfo, COL_RES_DL_DST, "BTS"); col_set_str(pinfo->cinfo, COL_RES_DL_SRC, "MS"); } else { switch (pinfo->pseudo_header->gsm_um.channel) { case GSM_UM_CHANNEL_BCCH: case GSM_UM_CHANNEL_CCCH: case GSM_UM_CHANNEL_PCH: case GSM_UM_CHANNEL_AGCH: col_set_str(pinfo->cinfo, COL_RES_DL_DST, "Broadcast"); break; default: col_set_str(pinfo->cinfo, COL_RES_DL_DST, "MS"); break; } col_set_str(pinfo->cinfo, COL_RES_DL_SRC, "BTS"); } if (tree) { const char *channel; ti = proto_tree_add_item(tree, proto_gsm_um, tvb, 0, 0, ENC_NA); gsm_um_tree = proto_item_add_subtree(ti, ett_gsm_um); switch( pinfo->pseudo_header->gsm_um.channel ) { case GSM_UM_CHANNEL_BCCH: channel = "BCCH"; break; case GSM_UM_CHANNEL_CCCH: channel = "CCCH"; break; case GSM_UM_CHANNEL_PCH: channel = "PCH"; break; case GSM_UM_CHANNEL_AGCH: channel = "AGCH"; break; case GSM_UM_CHANNEL_SACCH: channel = "SACCH"; break; case GSM_UM_CHANNEL_FACCH: channel = "FACCH"; break; case GSM_UM_CHANNEL_SDCCH: channel = "SDCCH"; break; default: channel = "Unknown"; break; } if( pinfo->pseudo_header->gsm_um.uplink ) { proto_tree_add_string(gsm_um_tree, hf_gsm_um_direction, tvb, 0, 0, "Uplink"); } else { proto_tree_add_string(gsm_um_tree, hf_gsm_um_direction, tvb, 0, 0, "Downlink"); } proto_tree_add_string(gsm_um_tree, hf_gsm_um_channel, tvb, 0, 0, channel); /* Show the other fields, if we have them (ie. downlink, BTS->MS) */ if( !pinfo->pseudo_header->gsm_um.uplink ) { const char *band; guint downlink, uplink; decode_arfcn(pinfo->pseudo_header->gsm_um.arfcn, &band, &uplink, &downlink); proto_tree_add_uint(gsm_um_tree, hf_gsm_um_arfcn, tvb, 0, 0, pinfo->pseudo_header->gsm_um.arfcn); proto_tree_add_string(gsm_um_tree, hf_gsm_um_band, tvb, 0, 0, band); proto_tree_add_uint_format_value(gsm_um_tree, hf_gsm_um_frequency, tvb, 0, 0, downlink, "%u.%03uMHz", downlink / 1000, downlink % 1000); proto_tree_add_uint(gsm_um_tree, hf_gsm_um_bsic, tvb, 0, 0, pinfo->pseudo_header->gsm_um.bsic); proto_tree_add_uint(gsm_um_tree, hf_gsm_um_frame, tvb, 0, 0, pinfo->pseudo_header->gsm_um.tdma_frame); proto_tree_add_uint(gsm_um_tree, hf_gsm_um_error, tvb, 0, 0, pinfo->pseudo_header->gsm_um.error); proto_tree_add_uint(gsm_um_tree, hf_gsm_um_timeshift, tvb, 0, 0, pinfo->pseudo_header->gsm_um.timeshift); } } /* TODO: If CCCH downlink could work out of PCH or AGCH by peeking at next bytes, uplink is RACH */ switch( pinfo->pseudo_header->gsm_um.channel ) { case GSM_UM_CHANNEL_BCCH: case GSM_UM_CHANNEL_CCCH: case GSM_UM_CHANNEL_PCH: case GSM_UM_CHANNEL_AGCH: if( !pinfo->pseudo_header->gsm_um.uplink ) { tvbuff_t *next_tvb; guint8 pseudo_len, len_left, len_byte; len_left = tvb_length(tvb); len_byte = tvb_get_guint8(tvb, 0); pseudo_len = len_byte >> 2; next_tvb = tvb_new_subset(tvb, 1, MIN(len_left, pseudo_len), -1); if (tree) { proto_tree_add_uint(gsm_um_tree, hf_gsm_um_l2_pseudo_len, tvb, 0, 1, len_byte); } /* Only dissect non-empty frames */ if( tvb_length(next_tvb) ) { call_dissector(dtap_handle, next_tvb, pinfo, tree); } } else {
static int dissect_text_lines(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) { proto_tree *subtree; proto_item *ti; gint offset = 0, next_offset; gint len; const char *data_name; int length = tvb_length(tvb); /* Check if this is actually xml * If there is less than 38 characters this is not XML * <?xml version="1.0" encoding="UTF-8"?> */ if(length > 38){ if (tvb_strncaseeql(tvb, 0, "<?xml", 5) == 0){ call_dissector(xml_handle, tvb, pinfo, tree); return tvb_length(tvb); } } data_name = pinfo->match_string; if (! (data_name && data_name[0])) { /* * No information from "match_string" */ data_name = (char *)data; if (! (data_name && data_name[0])) { /* * No information from dissector data */ data_name = (char *)(pinfo->private_data); if (! (data_name && data_name[0])) { /* * No information from "private_data" */ data_name = NULL; } } } if (data_name) col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "(%s)", data_name); if (tree) { ti = proto_tree_add_item(tree, proto_text_lines, tvb, 0, -1, ENC_NA); if (data_name) proto_item_append_text(ti, ": %s", data_name); subtree = proto_item_add_subtree(ti, ett_text_lines); /* Read the media line by line */ while (tvb_reported_length_remaining(tvb, offset) != 0) { /* * XXX - we need to be passed the parameters * of the content type via "pinfo->private_data", * so that we know the character set. We'd * have to handle that character set, which * might be a multibyte character set such * as "iso-10646-ucs-2", or might require other * special processing. */ len = tvb_find_line_end(tvb, offset, tvb_ensure_length_remaining(tvb, offset), &next_offset, FALSE); if (len == -1) break; /* We use next_offset - offset instead of len in the * call to tvb_format_text() so it will include the * line terminator(s) (\r and/or \n) in the display. */ proto_tree_add_text(subtree, tvb, offset, next_offset - offset, "%s", tvb_format_text(tvb, offset, next_offset - offset)); offset = next_offset; } } return tvb_length(tvb); }
/* This function is only called from the IGMP dissector */ int dissect_pimv1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset) { guint8 pim_type; guint8 pim_ver; guint length, pim_length; guint16 pim_cksum, computed_cksum; vec_t cksum_vec[1]; proto_tree *pim_tree = NULL; proto_item *ti; proto_tree *pimopt_tree = NULL; proto_item *tiopt; if (!proto_is_protocol_enabled(find_protocol_by_id(proto_pim))) { /* * We are not enabled; skip entire packet to be nice to the * IGMP layer (so clicking on IGMP will display the data). */ return offset+tvb_length_remaining(tvb, offset); } col_set_str(pinfo->cinfo, COL_PROTOCOL, "PIMv1"); col_clear(pinfo->cinfo, COL_INFO); ti = proto_tree_add_item(tree, proto_pim, tvb, offset, -1, FALSE); pim_tree = proto_item_add_subtree(ti, ett_pim); /* Put IGMP type, 0x14, into the tree */ proto_tree_add_text(pim_tree, tvb, offset, 1, "Type: PIM (0x14)"); offset += 1; pim_type = tvb_get_guint8(tvb, offset); if (check_col(pinfo->cinfo, COL_INFO)) col_add_str(pinfo->cinfo, COL_INFO, val_to_str(pim_type, type1vals, "Unknown (%u)")); proto_tree_add_uint(pim_tree, hf_pim_code, tvb, offset, 1, pim_type); offset += 1; pim_cksum = tvb_get_ntohs(tvb, offset); pim_ver = PIM_VER(tvb_get_guint8(tvb, offset + 2)); if (pim_ver != 1) { /* * Not PIMv1 - what gives? */ proto_tree_add_uint(pim_tree, hf_pim_cksum, tvb, offset, 2, pim_cksum); offset += 2; proto_tree_add_item(pim_tree, hf_pim_version, tvb, offset, 1, FALSE); return offset+tvb_length_remaining(tvb, offset); } /* * Well, it's PIM v1, so we can check whether this is a * Register message, and thus can figure out how much to * checksum and whether to make the columns read-only. */ length = tvb_length(tvb); if (pim_type == 1) { /* * Register message - the PIM header is 8 bytes long. * Also set the columns non-writable. Otherwise the IPv4 or * IPv6 dissector for the encapsulated packet that caused * this register will overwrite the PIM info in the columns. */ pim_length = 8; col_set_writable(pinfo->cinfo, FALSE); } else { /* * Other message - checksum the entire packet. */ pim_length = tvb_reported_length(tvb); } if (!pinfo->fragmented && length >= pim_length) { /* * The packet isn't part of a fragmented datagram and isn't * truncated, so we can checksum it. */ cksum_vec[0].ptr = tvb_get_ptr(tvb, 0, pim_length); cksum_vec[0].len = pim_length; computed_cksum = in_cksum(&cksum_vec[0], 1); if (computed_cksum == 0) { proto_tree_add_uint_format(pim_tree, hf_pim_cksum, tvb, offset, 2, pim_cksum, "Checksum: 0x%04x [correct]", pim_cksum); } else { proto_tree_add_uint_format(pim_tree, hf_pim_cksum, tvb, offset, 2, pim_cksum, "Checksum: 0x%04x [incorrect, should be 0x%04x]", pim_cksum, in_cksum_shouldbe(pim_cksum, computed_cksum)); } } else { proto_tree_add_uint(pim_tree, hf_pim_cksum, tvb, offset, 2, pim_cksum); } offset += 2; proto_tree_add_item(pim_tree, hf_pim_version, tvb, offset, 1, FALSE); offset += 1; offset += 3; /* skip reserved stuff */ if (tvb_reported_length_remaining(tvb, offset) > 0) { tiopt = proto_tree_add_text(pim_tree, tvb, offset, -1, "PIM options"); pimopt_tree = proto_item_add_subtree(tiopt, ett_pim_opts); } else goto done; /* version 1 decoder */ switch (pim_type) { case 0: /* query */ { guint16 holdtime; proto_tree_add_item(pimopt_tree, hf_pim_mode, tvb, offset, 1, FALSE); offset += 2; holdtime = tvb_get_ntohs(tvb, offset); proto_tree_add_uint_format(pimopt_tree, hf_pim_holdtime, tvb, offset, 2, holdtime, "Holdtime: %us %s", holdtime, holdtime == 0xffff ? "(infinity)": ""); offset += 2; break; } case 1: /* register */ { guint8 v_hl; tvbuff_t *next_tvb; /* * The rest of the packet is a multicast data packet. */ next_tvb = tvb_new_subset_remaining(tvb, offset); /* * It's an IP packet - determine whether it's IPv4 or IPv6. */ v_hl = tvb_get_guint8(tvb, offset); switch((v_hl & 0xf0) >> 4) { case 0: /* Null-Register dummy header. * Has the same address family as the encapsulating PIM packet, * e.g. an IPv6 data packet is encapsulated in IPv6 PIM packet. */ if (pinfo->src.type == AT_IPv4) { proto_tree_add_text(pimopt_tree, tvb, offset, -1, "IPv4 dummy header"); proto_tree_add_text(pimopt_tree, tvb, offset + 12, 4, "Source: %s", tvb_ip_to_str(tvb, offset + 12)); proto_tree_add_text(pimopt_tree, tvb, offset + 16, 4, "Group: %s", tvb_ip_to_str(tvb, offset + 16)); } else if (pinfo->src.type == AT_IPv6) { proto_tree_add_text(pimopt_tree, tvb, offset, -1, "IPv6 dummy header"); proto_tree_add_text(pimopt_tree, tvb, offset + 8, 16, "Source: %s", tvb_ip6_to_str(tvb, offset + 8)); proto_tree_add_text(pimopt_tree, tvb, offset + 8 + 16, 16, "Group: %s", tvb_ip6_to_str(tvb, offset + 8)); } else proto_tree_add_text(pimopt_tree, tvb, offset, -1, "Dummy header for an unknown protocol"); break; case 4: /* IPv4 */ #if 0 call_dissector(ip_handle, next_tvb, pinfo, tree); #else call_dissector(ip_handle, next_tvb, pinfo, pimopt_tree); #endif break; case 6: /* IPv6 */ #if 0 call_dissector(ipv6_handle, next_tvb, pinfo, tree); #else call_dissector(ipv6_handle, next_tvb, pinfo, pimopt_tree); #endif break; default: proto_tree_add_text(pimopt_tree, tvb, offset, -1, "Unknown IP version %d", (v_hl & 0xf0) >> 4); break; } break; } case 2: /* register-stop */ { proto_tree_add_text(pimopt_tree, tvb, offset, 4, "Group: %s", tvb_ip_to_str(tvb, offset)); offset += 4; proto_tree_add_text(pimopt_tree, tvb, offset, 4, "Source: %s", tvb_ip_to_str(tvb, offset)); offset += 4; break; } case 3: /* join/prune */ case 6: /* graft */ case 7: /* graft-ack */ { int off; const char *s; int ngroup, i, njoin, nprune, j; guint16 holdtime; guint8 mask_len; guint8 adr_len; proto_tree *grouptree = NULL; proto_item *tigroup; proto_tree *subtree = NULL; proto_item *tisub; proto_tree_add_text(pimopt_tree, tvb, offset, 4, "Upstream-neighbor: %s", tvb_ip_to_str(tvb, offset)); offset += 4; offset += 2; /* skip reserved stuff */ holdtime = tvb_get_ntohs(tvb, offset); proto_tree_add_uint_format(pimopt_tree, hf_pim_holdtime, tvb, offset, 2, holdtime, "Holdtime: %us %s", holdtime, holdtime == 0xffff ? "(infinity)": ""); offset += 2; offset += 1; /* skip reserved stuff */ mask_len = tvb_get_guint8(tvb, offset); proto_tree_add_text(pimopt_tree, tvb, offset, 1, "Mask length: %u", mask_len); offset += 1; adr_len = tvb_get_guint8(tvb, offset); proto_tree_add_text(pimopt_tree, tvb, offset, 1, "Address length: %u", adr_len); offset += 1; ngroup = tvb_get_guint8(tvb, offset); proto_tree_add_item(pimopt_tree, hf_pim_numgroups, tvb, offset, 1, FALSE); offset += 1; for (i = 0; i < ngroup; i++) { /* * XXX - does the group address have the length "adr_len" * and the group mask the length "mask_len"? */ tigroup = proto_tree_add_text(pimopt_tree, tvb, offset, 4, "Group %d: %s", i, tvb_ip_to_str(tvb, offset)); grouptree = proto_item_add_subtree(tigroup, ett_pim); offset += 4; proto_tree_add_text(grouptree, tvb, offset, 4, "Group %d Mask: %s", i, tvb_ip_to_str(tvb, offset)); offset += 4; njoin = tvb_get_ntohs(tvb, offset); nprune = tvb_get_ntohs(tvb, offset + 2); tisub = proto_tree_add_item(grouptree, hf_pim_numjoins, tvb, offset, 2, FALSE); subtree = proto_item_add_subtree(tisub, ett_pim); off = offset + 4; for (j = 0; j < njoin; j++) { s = dissect_pimv1_addr(tvb, off); proto_tree_add_text(subtree, tvb, off, 6, "IP address: %s", s); off += 6; } tisub = proto_tree_add_item(grouptree, hf_pim_numprunes, tvb, offset + 2, 2, FALSE); subtree = proto_item_add_subtree(tisub, ett_pim); for (j = 0; j < nprune; j++) { s = dissect_pimv1_addr(tvb, off); proto_tree_add_text(subtree, tvb, off, 6, "IP address: %s", s); off += 6; } offset = off; } break; } case 4: /* rp-reachability */ { guint16 holdtime; proto_tree_add_text(pimopt_tree, tvb, offset, 4, "Group Address: %s", tvb_ip_to_str(tvb, offset)); offset += 4; proto_tree_add_text(pimopt_tree, tvb, offset, 4, "Group Mask: %s", tvb_ip_to_str(tvb, offset)); offset += 4; proto_tree_add_text(pimopt_tree, tvb, offset, 4, "RP Address: %s", tvb_ip_to_str(tvb, offset)); offset += 4; offset += 2; /* skip reserved stuff */ holdtime = tvb_get_ntohs(tvb, offset); proto_tree_add_uint_format(pimopt_tree, hf_pim_holdtime, tvb, offset, 2, holdtime, "Holdtime: %us %s", holdtime, holdtime == 0xffff ? "(infinity)": ""); offset += 2; break; } case 5: /* assert */ { guint32 pref; proto_tree_add_text(pimopt_tree, tvb, offset, 4, "Group Address: %s", tvb_ip_to_str(tvb, offset)); offset += 4; proto_tree_add_text(pimopt_tree, tvb, offset, 4, "Group Mask: %s", tvb_ip_to_str(tvb, offset)); offset += 4; proto_tree_add_item(pimopt_tree, hf_pim_rpt, tvb, offset, 1, FALSE); pref = tvb_get_ntohl(tvb, offset) & 0x7fffffff; proto_tree_add_uint_format(pimopt_tree, hf_pim_metric_pref, tvb, offset, 4, pref, "Metric Preference: %u", pref); offset += 4; proto_tree_add_item(pimopt_tree, hf_pim_metric, tvb, offset, 4, FALSE); offset += 4; break; } default: break; } done:; return offset+tvb_length_remaining(tvb, offset); }
static gboolean dissect_fcip (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean check_port) { gint offset = 0, start = 0, frame_len = 0; gint bytes_remaining = tvb_length (tvb); guint8 pflags, sof = 0, eof = 0; /* Set up structures needed to add the protocol subtree and manage it */ proto_item *ti; proto_tree *fcip_tree = NULL; tvbuff_t *next_tvb; if (bytes_remaining < FCIP_ENCAP_HEADER_LEN) { return FALSE; } if (check_port && ((pinfo->srcport != fcip_port) && (pinfo->destport != fcip_port))) { return FALSE; } while (bytes_remaining > FCIP_ENCAP_HEADER_LEN) { if ((offset = get_next_fcip_header_offset (tvb, pinfo, offset)) == -1) { return FALSE; } else if (offset == -2) { /* We need more data to desegment */ return (TRUE); } start = offset; col_set_str(pinfo->cinfo, COL_PROTOCOL, "FCIP"); frame_len = (tvb_get_ntohs (tvb, offset+12) & 0x03FF)*4; if (bytes_remaining < frame_len) { if(fcip_desegment && pinfo->can_desegment) { /* * This frame doesn't have all of the data for * this message, but we can do reassembly on it. * * Tell the TCP dissector where the data for this * message starts in the data it handed us, and * how many more bytes we need, and return. */ pinfo->desegment_offset = offset; pinfo->desegment_len = frame_len - bytes_remaining; return (TRUE); } } pflags = tvb_get_guint8 (tvb, start+8); if (tree) { if (FCIP_IS_SF (pflags)) { ti = proto_tree_add_protocol_format (tree, proto_fcip, tvb, 0, FCIP_ENCAP_HEADER_LEN, "FCIP"); } else if (tvb_bytes_exist (tvb, offset, offset+frame_len-4)) { sof = tvb_get_guint8 (tvb, offset+FCIP_ENCAP_HEADER_LEN); eof = tvb_get_guint8 (tvb, offset+frame_len - 4); ti = proto_tree_add_protocol_format (tree, proto_fcip, tvb, 0, FCIP_ENCAP_HEADER_LEN, "FCIP (%s/%s)", val_to_str (sof, fcip_sof_vals, "0x%x"), val_to_str (eof, fcip_eof_vals, "0x%x")); } else { sof = tvb_get_guint8 (tvb, offset+FCIP_ENCAP_HEADER_LEN); ti = proto_tree_add_protocol_format (tree, proto_fcip, tvb, 0, FCIP_ENCAP_HEADER_LEN, "FCIP (%s/%s)", val_to_str (sof, fcip_sof_vals, "0x%x"), "NA"); } fcip_tree = proto_item_add_subtree (ti, ett_fcip); /* Dissect the Common FC Encap header */ dissect_fcencap_header (tvb, fcip_tree, offset); offset += FCIP_ENCAP_HEADER_LEN; if (!FCIP_IS_SF (pflags)) { /* print SOF */ proto_tree_add_item (fcip_tree, hf_fcip_sof, tvb, offset, 1, 0); proto_tree_add_item (fcip_tree, hf_fcip_sof_c, tvb, offset+2, 1, 0); /* print EOF */ offset += (frame_len-FCIP_ENCAP_HEADER_LEN-4); if (tvb_bytes_exist (tvb, offset, 4)) { proto_tree_add_item (fcip_tree, hf_fcip_eof, tvb, offset, 1, 0); proto_tree_add_item (fcip_tree, hf_fcip_eof_c, tvb, offset+2, 1, 0); } } } /* Call the FC Dissector if this is carrying an FC frame */ if (!FCIP_IS_SF(pflags)) { /* Set the SOF/EOF flags in the packet_info header */ pinfo->sof_eof = 0; if (sof) { if ((sof == FCIP_SOFi3) || (sof == FCIP_SOFi2) || (sof == FCIP_SOFi4)) { pinfo->sof_eof = PINFO_SOF_FIRST_FRAME; } else if (sof == FCIP_SOFf) { pinfo->sof_eof = PINFO_SOF_SOFF; } if (eof != FCIP_EOFn) { pinfo->sof_eof |= PINFO_EOF_LAST_FRAME; } else if (eof != FCIP_EOFt) { pinfo->sof_eof |= PINFO_EOF_INVALID; } } /* Special frame bit is not set */ next_tvb = tvb_new_subset_remaining (tvb, FCIP_ENCAP_HEADER_LEN+4); if (fc_handle) { call_dissector (fc_handle, next_tvb, pinfo, tree); } else if (data_handle) { call_dissector (data_handle, next_tvb, pinfo, tree); } } else { col_set_str(pinfo->cinfo, COL_INFO, "Special Frame"); if (FCIP_IS_CH (pflags)) { col_append_str(pinfo->cinfo, COL_INFO, "(Changed)"); } dissect_fcip_sf (tvb, fcip_tree, offset+4); } bytes_remaining -= frame_len; } return (TRUE); }
/* XXX: Are all the tests against tvb_length() really the right way to handle invalid fields ? * It seems to me that invalid fields should just add an expert item * or cause a "Malformed" exception. */ static void dissect_elcom(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { gboolean is_request, length_ok; proto_tree *elcom_tree; proto_item *ti, *hidden_item; gint offset = 0; guint elcom_len; guint8 elcom_msg_type; guint8 *suffix; /* Check that there's enough data */ if (tvb_length(tvb) < 3) return; col_set_str(pinfo->cinfo, COL_PROTOCOL, "ELCOM"); col_clear(pinfo->cinfo, COL_INFO); is_request = (pinfo->match_port == pinfo->destport); elcom_len = tvb_get_ntohs(tvb, 0); length_ok = (tvb_reported_length(tvb) == (elcom_len+2)); col_add_fstr(pinfo->cinfo, COL_INFO, "%s Len=%d%s", is_request ? "Request" : "Response", elcom_len, length_ok ? "" : " (incorrect)"); elcom_msg_type = tvb_get_guint8(tvb, 2); switch (elcom_msg_type) { case P_CONRQ: case P_CONRS: /* starting after elcom_len and elcom_msg_type, initiator + responder + userdata fields must be there */ if (tvb_length_remaining(tvb, 3+TOTAL_LEN+TOTAL_LEN+3) < 0) return; /* check also that those field lengths are valid */ if (tvb_get_guint8(tvb, 3) != LOWADR_LEN) return; if (tvb_get_guint8(tvb, 3+1+LOWADR_LEN) != SUFFIX_LEN) return; if (tvb_get_guint8(tvb, 3+TOTAL_LEN) != LOWADR_LEN) return; if (tvb_get_guint8(tvb, 3+1+TOTAL_LEN+LOWADR_LEN) != SUFFIX_LEN) return; /* finally believe that there is valid suffix */ suffix = tvb_get_string(wmem_packet_scope(), tvb, 3+2+LOWADR_LEN, 2); col_append_fstr(pinfo->cinfo, COL_INFO, " %s Connect", suffix); break; case P_RELRQ: case P_RELRS: col_append_str(pinfo->cinfo, COL_INFO, " Release"); break; case P_DATRQ: col_append_str(pinfo->cinfo, COL_INFO, " Data"); break; } switch (elcom_msg_type) { case P_CONRQ: case P_RELRQ: col_append_str(pinfo->cinfo, COL_INFO, " Request"); break; case P_CONRS: case P_RELRS: col_append_str(pinfo->cinfo, COL_INFO, " Response"); break; } if (!tree) return; ti = proto_tree_add_item(tree, proto_elcom, tvb, offset, -1, ENC_NA); elcom_tree = proto_item_add_subtree(ti, ett_elcom); hidden_item = proto_tree_add_boolean(elcom_tree, is_request ? hf_elcom_request : hf_elcom_response, tvb, 0, 0, TRUE); PROTO_ITEM_SET_HIDDEN(hidden_item); /* 2 first bytes are the frame length */ offset = 0; ti = proto_tree_add_item(elcom_tree, hf_elcom_length, tvb, offset, 2, ENC_BIG_ENDIAN); offset = +2; if (! length_ok) { proto_item_append_text(ti, " (incorrect)"); } elcom_msg_type = tvb_get_guint8(tvb, offset); ti = proto_tree_add_item(elcom_tree, hf_elcom_type, tvb, offset, 1, ENC_BIG_ENDIAN); proto_item_append_text(elcom_tree, " ( %s)", val_to_str(elcom_msg_type, type_vals, "Unknown %d")); offset++; if (tvb_length_remaining(tvb, offset) <= 0) return; switch (elcom_msg_type) { case P_CONRQ: case P_CONRS: /* * Connection request/release assiciated PDU's, * /ELCOM-90 P Protocol spec/ p. 85... */ /* We need the length here, hardcode the LOWADR_LEN = 21 */ ti = proto_tree_add_item(elcom_tree, hf_elcom_initiator, tvb, offset, TOTAL_LEN, ENC_BIG_ENDIAN); offset = dissect_lower_address(ti, ett_elcom_initiator, tvb, offset, hf_elcom_initiator_endian, hf_elcom_initiator_ip, hf_elcom_initiator_port, hf_elcom_initiator_suff); if (tvb_length_remaining(tvb, offset) <= 0) return; ti = proto_tree_add_item(elcom_tree, hf_elcom_responder, tvb, offset, TOTAL_LEN, ENC_BIG_ENDIAN); offset = dissect_lower_address(ti, ett_elcom_responder, tvb, offset, hf_elcom_responder_endian, hf_elcom_responder_ip, hf_elcom_responder_port, hf_elcom_responder_suff); if (tvb_length_remaining(tvb, offset) <= 0) return; /* Rest of the payload is USER-DATA, 0..82 bytes */ ti = proto_tree_add_item(elcom_tree, hf_elcom_userdata, tvb, offset, -1, ENC_NA); offset = dissect_userdata(ti, ett_elcom_userdata, tvb, offset); break; case P_RELRQ: proto_tree_add_item(elcom_tree, hf_elcom_release_reason, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; case P_RELRS: proto_tree_add_item(elcom_tree, hf_elcom_release_result, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; case P_DATRQ: ti = proto_tree_add_item(elcom_tree, hf_elcom_datarequest, tvb, offset, -1, ENC_NA); offset = dissect_datarequest(ti, ett_elcom_datarequest, tvb, offset); break; default: proto_item_append_text(ti, " <<--- meaning WHAT??"); break; } if (tvb_length_remaining(tvb, offset) <= 0) return; /* We should not get here, but if we do, show what is left over: */ ti = proto_tree_add_item(elcom_tree, hf_elcom_strangeleftover, tvb, offset, -1, ENC_NA); while (tvb_length_remaining(tvb, offset) > 0) { proto_item_append_text(ti, elcom_show_hex ? " %02x" : " %03o", tvb_get_guint8(tvb, offset)); offset++; } }
static void dissect_drda(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { gint offset = 0; guint16 iCommand; guint16 iLength; guint16 iCommandEnd = 0; guint8 iFormatFlags; guint8 iDSSType; guint8 iDSSFlags; guint16 iParameterCP; gint iLengthParam; col_set_str(pinfo->cinfo, COL_PROTOCOL, "DRDA"); /* This is a trick to know whether this is the first PDU in this packet or not */ if (iPreviousFrameNumber != pinfo->fd->num) col_clear(pinfo->cinfo, COL_INFO); else col_append_str(pinfo->cinfo, COL_INFO, " | "); iPreviousFrameNumber = pinfo->fd->num; /* There may be multiple DRDA commands in one frame */ while ((guint) (offset + 10) <= tvb_length(tvb)) { iCommand = tvb_get_ntohs(tvb, offset + 8); iLength = tvb_get_ntohs(tvb, offset + 0); if (iLength < 10) { expert_add_info_format_text(pinfo, NULL, &ei_drda_opcode_invalid_length, "Invalid length detected (%u): should be at least 10 bytes long", iLength); break; } /* iCommandEnd is the length of the packet up to the end of the current command */ iCommandEnd += iLength; if (offset > 0) col_append_str(pinfo->cinfo, COL_INFO, " | "); col_append_str(pinfo->cinfo, COL_INFO, val_to_str_ext(iCommand, &drda_opcode_abbr_ext, "Unknown (0x%02x)")); if (tree) { proto_tree *drda_tree; proto_tree *drdaroot_tree; proto_tree *drda_tree_sub; proto_item *ti; ti = proto_tree_add_item(tree, proto_drda, tvb, offset, -1, ENC_NA); proto_item_append_text(ti, " (%s)", val_to_str_ext(iCommand, &drda_opcode_vals_ext, "Unknown (0x%02x)")); drdaroot_tree = proto_item_add_subtree(ti, ett_drda); ti = proto_tree_add_text(drdaroot_tree, tvb, offset, 10, DRDA_TEXT_DDM); proto_item_append_text(ti, " (%s)", val_to_str_ext(iCommand, &drda_opcode_abbr_ext, "Unknown (0x%02x)")); drda_tree = proto_item_add_subtree(ti, ett_drda_ddm); proto_tree_add_item(drda_tree, hf_drda_ddm_length, tvb, offset + 0, 2, ENC_BIG_ENDIAN); proto_tree_add_item(drda_tree, hf_drda_ddm_magic, tvb, offset + 2, 1, ENC_BIG_ENDIAN); iFormatFlags = tvb_get_guint8(tvb, offset + 3); iDSSType = iFormatFlags & 0x0F; iDSSFlags = iFormatFlags >> 4; ti = proto_tree_add_item(drda_tree, hf_drda_ddm_format, tvb, offset + 3, 1, ENC_BIG_ENDIAN); drda_tree_sub = proto_item_add_subtree(ti, ett_drda_ddm_format); proto_tree_add_boolean(drda_tree_sub, hf_drda_ddm_fmt_reserved, tvb, offset + 3, 1, iDSSFlags); proto_tree_add_boolean(drda_tree_sub, hf_drda_ddm_fmt_chained, tvb, offset + 3, 1, iDSSFlags); proto_tree_add_boolean(drda_tree_sub, hf_drda_ddm_fmt_errcont, tvb, offset + 3, 1, iDSSFlags); proto_tree_add_boolean(drda_tree_sub, hf_drda_ddm_fmt_samecorr, tvb, offset + 3, 1, iDSSFlags); proto_tree_add_uint(drda_tree_sub, hf_drda_ddm_fmt_dsstyp, tvb, offset + 3, 1, iDSSType); proto_tree_add_item(drda_tree, hf_drda_ddm_rc, tvb, offset + 4, 2, ENC_BIG_ENDIAN); proto_tree_add_item(drda_tree, hf_drda_ddm_length2, tvb, offset + 6, 2, ENC_BIG_ENDIAN); proto_tree_add_item(drda_tree, hf_drda_ddm_codepoint, tvb, offset + 8, 2, ENC_BIG_ENDIAN); /* The number of attributes is variable */ for (offset += 10; offset < iCommandEnd; ) { if (tvb_length_remaining(tvb, offset) >= 2) { iLengthParam = tvb_get_ntohs(tvb, offset + 0); if (iLengthParam == 0 || iLengthParam == 1) iLengthParam = iLength - 10; if (tvb_length_remaining(tvb, offset) >= iLengthParam) { iParameterCP = tvb_get_ntohs(tvb, offset + 2); ti = proto_tree_add_text(drdaroot_tree, tvb, offset, iLengthParam, DRDA_TEXT_PARAM); proto_item_append_text(ti, " (%s)", val_to_str_ext(iParameterCP, &drda_opcode_vals_ext, "Unknown (0x%02x)")); drda_tree_sub = proto_item_add_subtree(ti, ett_drda_param); proto_tree_add_item(drda_tree_sub, hf_drda_param_length, tvb, offset, 2, ENC_BIG_ENDIAN); proto_tree_add_item(drda_tree_sub, hf_drda_param_codepoint, tvb, offset + 2, 2, ENC_BIG_ENDIAN); proto_tree_add_item(drda_tree_sub, hf_drda_param_data, tvb, offset + 4, iLengthParam - 4, ENC_UTF_8|ENC_NA); proto_tree_add_item(drda_tree_sub, hf_drda_param_data_ebcdic, tvb, offset + 4, iLengthParam - 4, ENC_EBCDIC|ENC_NA); if (iCommand == DRDA_CP_SQLSTT) { /* Extract SQL statement from packet */ tvbuff_t* next_tvb = NULL; next_tvb = tvb_new_subset(tvb, offset + 4, iLengthParam - 4, iLengthParam - 4); add_new_data_source(pinfo, next_tvb, "SQL statement"); proto_tree_add_item(drdaroot_tree, hf_drda_sqlstatement, next_tvb, 0, iLengthParam - 5, ENC_UTF_8|ENC_NA); proto_tree_add_item(drdaroot_tree, hf_drda_sqlstatement_ebcdic, next_tvb, 0, iLengthParam - 4, ENC_EBCDIC|ENC_NA); } } offset += iLengthParam; } else { break; } } } else { /* No tree, advance directly to next command */ offset += iLength; } }
static void dissect_exec(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { /* Set up structures needed to add the protocol subtree and manage it */ proto_item *ti; proto_tree *exec_tree=NULL; /* Variables for extracting and displaying data from the packet */ guchar *field_stringz; /* Temporary storage for each field we extract */ gint length; guint offset = 0; conversation_t *conversation; exec_hash_entry_t *hash_info; conversation = find_or_create_conversation(pinfo); /* Retrieve information from conversation * or add it if it isn't there yet */ hash_info = (exec_hash_entry_t *)conversation_get_proto_data(conversation, proto_exec); if(!hash_info){ hash_info = wmem_new(wmem_file_scope(), exec_hash_entry_t); hash_info->first_packet_number = pinfo->fd->num; hash_info->second_packet_number = 0; hash_info->third_packet_number = 0; hash_info->fourth_packet_number = 0; hash_info->state = WAIT_FOR_STDERR_PORT; /* The first field we'll see */ /* Start with empty username and command strings */ hash_info->username=NULL; hash_info->command=NULL; /* These will be set on the first pass by the first * four packets of the conversation */ hash_info->first_packet_state = NONE; hash_info->second_packet_state = NONE; hash_info->third_packet_state = NONE; hash_info->fourth_packet_state = NONE; conversation_add_proto_data(conversation, proto_exec, hash_info); } /* Store the number of the first three packets of this conversation * as we reach them the first time */ if(!hash_info->second_packet_number && pinfo->fd->num > hash_info->first_packet_number){ /* We're on the second packet of the conversation */ hash_info->second_packet_number = pinfo->fd->num; } else if(hash_info->second_packet_number && !hash_info->third_packet_number && pinfo->fd->num > hash_info->second_packet_number) { /* We're on the third packet of the conversation */ hash_info->third_packet_number = pinfo->fd->num; } else if(hash_info->third_packet_number && !hash_info->fourth_packet_number && pinfo->fd->num > hash_info->third_packet_number) { /* We're on the fourth packet of the conversation */ hash_info->fourth_packet_number = pinfo->fd->num; } /* Save this packet's state so we can retrieve it if this packet * is selected again later. If the packet's state was already stored, * then retrieve it */ if(pinfo->fd->num == hash_info->first_packet_number){ if(hash_info->first_packet_state == NONE){ hash_info->first_packet_state = hash_info->state; } else { hash_info->state = hash_info->first_packet_state; } } if(pinfo->fd->num == hash_info->second_packet_number){ if(hash_info->second_packet_state == NONE){ hash_info->second_packet_state = hash_info->state; } else { hash_info->state = hash_info->second_packet_state; } } if(pinfo->fd->num == hash_info->third_packet_number){ if(hash_info->third_packet_state == NONE){ hash_info->third_packet_state = hash_info->state; } else { hash_info->state = hash_info->third_packet_state; } } if(pinfo->fd->num == hash_info->fourth_packet_number){ if(hash_info->fourth_packet_state == NONE){ hash_info->fourth_packet_state = hash_info->state; } else { hash_info->state = hash_info->fourth_packet_state; } } col_set_str(pinfo->cinfo, COL_PROTOCOL, "EXEC"); /* First, clear the info column */ col_clear(pinfo->cinfo, COL_INFO); /*username */ if(hash_info->username && preference_info_show_username == TRUE){ col_append_fstr(pinfo->cinfo, COL_INFO, "Username:%s ", hash_info->username); } /* Command */ if(hash_info->command && preference_info_show_command == TRUE){ col_append_fstr(pinfo->cinfo, COL_INFO, "Command:%s ", hash_info->command); } /* create display subtree for the protocol */ ti = proto_tree_add_item(tree, proto_exec, tvb, 0, -1, ENC_NA); exec_tree = proto_item_add_subtree(ti, ett_exec); /* If this packet doesn't end with a null terminated string, * then it must be session data only and we can skip looking * for the other fields. */ if(tvb_find_guint8(tvb, tvb_length(tvb)-1, 1, '\0') == -1){ hash_info->state = WAIT_FOR_DATA; } if(hash_info->state == WAIT_FOR_STDERR_PORT && tvb_length_remaining(tvb, offset)){ field_stringz = tvb_get_stringz_enc(wmem_packet_scope(), tvb, offset, &length, ENC_ASCII); /* Check if this looks like the stderr_port field. * It is optional, so it may only be 1 character long * (the NULL) */ if(length == 1 || (isdigit_string(field_stringz) && length <= EXEC_STDERR_PORT_LEN)){ proto_tree_add_string(exec_tree, hf_exec_stderr_port, tvb, offset, length, (gchar*)field_stringz); /* Next field we need */ hash_info->state = WAIT_FOR_USERNAME; } else { /* Since the data doesn't match this field, it must be data only */ hash_info->state = WAIT_FOR_DATA; } /* Used if the next field is in the same packet */ offset += length; } if(hash_info->state == WAIT_FOR_USERNAME && tvb_length_remaining(tvb, offset)){ field_stringz = tvb_get_stringz_enc(wmem_packet_scope(), tvb, offset, &length, ENC_ASCII); /* Check if this looks like the username field */ if(length != 1 && length <= EXEC_USERNAME_LEN && isprint_string(field_stringz)){ proto_tree_add_string(exec_tree, hf_exec_username, tvb, offset, length, (gchar*)field_stringz); /* Store the username so we can display it in the * info column of the entire conversation */ if(!hash_info->username){ hash_info->username=wmem_strdup(wmem_file_scope(), (gchar*)field_stringz); } /* Next field we need */ hash_info->state = WAIT_FOR_PASSWORD; } else { /* Since the data doesn't match this field, it must be data only */ hash_info->state = WAIT_FOR_DATA; } /* Used if the next field is in the same packet */ offset += length; } if(hash_info->state == WAIT_FOR_PASSWORD && tvb_length_remaining(tvb, offset)){ field_stringz = tvb_get_stringz_enc(wmem_packet_scope(), tvb, offset, &length, ENC_ASCII); /* Check if this looks like the password field */ if(length != 1 && length <= EXEC_PASSWORD_LEN && isprint_string(field_stringz)){ proto_tree_add_string(exec_tree, hf_exec_password, tvb, offset, length, (gchar*)field_stringz); /* Next field we need */ hash_info->state = WAIT_FOR_COMMAND; } else { /* Since the data doesn't match this field, it must be data only */ hash_info->state = WAIT_FOR_DATA; } /* Used if the next field is in the same packet */ offset += length; /* Next field we are looking for */ hash_info->state = WAIT_FOR_COMMAND; } if(hash_info->state == WAIT_FOR_COMMAND && tvb_length_remaining(tvb, offset)){ field_stringz = tvb_get_stringz_enc(wmem_packet_scope(), tvb, offset, &length, ENC_ASCII); /* Check if this looks like the command field */ if(length != 1 && length <= EXEC_COMMAND_LEN && isprint_string(field_stringz)){ proto_tree_add_string(exec_tree, hf_exec_command, tvb, offset, length, (gchar*)field_stringz); /* Store the command so we can display it in the * info column of the entire conversation */ if(!hash_info->command){ hash_info->command=wmem_strdup(wmem_file_scope(), (gchar*)field_stringz); } } else { /* Since the data doesn't match this field, it must be data only */ hash_info->state = WAIT_FOR_DATA; } } if(hash_info->state == WAIT_FOR_DATA && tvb_length_remaining(tvb, offset)){ if(pinfo->destport == EXEC_PORT){ /* Packet going to the server */ /* offset = 0 since the whole packet is data */ proto_tree_add_item(exec_tree, hf_exec_client_server_data, tvb, 0, -1, ENC_NA); col_append_str(pinfo->cinfo, COL_INFO, "Client -> Server data"); } else { /* This packet must be going back to the client */ /* offset = 0 since the whole packet is data */ proto_tree_add_item(exec_tree, hf_exec_server_client_data, tvb, 0, -1, ENC_NA); col_append_str(pinfo->cinfo, COL_INFO, "Server -> Client Data"); } } /* We haven't seen all of the fields yet */ if(hash_info->state < WAIT_FOR_DATA){ col_set_str(pinfo->cinfo, COL_INFO, "Session Establishment"); } }
static void rs11(tvbuff_t *tvb, proto_tree *tree) { proto_tree_add_item(tree, hf_ipmi_stor_11_ret_count, tvb, 0, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(tree, hf_ipmi_stor_11_data, tvb, 1, tvb_length(tvb) - 1, ENC_NA); }
static int dissect_gopher(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_item *ti; proto_tree *gopher_tree, *dir_tree = NULL; gboolean client = is_client(pinfo); gint line_len; const gchar *request = "[Invalid request]"; gboolean is_dir = FALSE; gint offset = 0, next_offset; gint sel_start, host_start, port_start; gchar *name; /* Fill in our protocol and info columns */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "Gopher"); if (client) { line_len = tvb_find_line_end(tvb, 0, -1, NULL, FALSE); if (line_len == 0) { request = "[Directory list]"; } else if (line_len > 0) { request = tvb_get_ephemeral_string(tvb, 0, line_len); } col_add_fstr(pinfo->cinfo, COL_INFO, "Request: %s", request); } else { col_add_fstr(pinfo->cinfo, COL_INFO, "Response"); } if (tree) { /* Create display subtree for the protocol */ ti = proto_tree_add_item(tree, proto_gopher, tvb, 0, -1, ENC_NA); gopher_tree = proto_item_add_subtree(ti, ett_gopher); if (client) { proto_item_append_text(ti, " request: %s", request); proto_tree_add_string(gopher_tree, hf_gopher_request, tvb, 0, -1, request); } else { proto_item_append_text(ti, " response: "); while (find_dir_tokens(tvb, offset + 1, &sel_start, &host_start, &port_start, &line_len, &next_offset)) { if (!is_dir) { /* First time */ proto_item_append_text(ti, "[Directory list]"); col_append_fstr(pinfo->cinfo, COL_INFO, ": [Directory list]"); } name = tvb_get_string(tvb, offset + 1, sel_start - offset - 2); ti = proto_tree_add_string(gopher_tree, hf_gopher_dir_item, tvb, offset, line_len + 1, name); g_free(name); dir_tree = proto_item_add_subtree(ti, ett_dir_item); proto_tree_add_item(dir_tree, hf_gopher_di_type, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(dir_tree, hf_gopher_di_name, tvb, offset + 1, sel_start - offset - 2, ENC_ASCII|ENC_NA); proto_tree_add_item(dir_tree, hf_gopher_di_selector, tvb, sel_start, host_start - sel_start - 1, ENC_ASCII|ENC_NA); proto_tree_add_item(dir_tree, hf_gopher_di_host, tvb, host_start, port_start - host_start - 1, ENC_ASCII|ENC_NA); proto_tree_add_item(dir_tree, hf_gopher_di_port, tvb, port_start, line_len - (port_start - offset - 1), ENC_ASCII|ENC_NA); is_dir = TRUE; offset = next_offset; } if (!is_dir) { proto_item_append_text(ti, "[Unknown]"); proto_tree_add_item(gopher_tree, hf_gopher_unknown, tvb, 0, -1, ENC_ASCII|ENC_NA); } } } /* Return the amount of data this dissector was able to dissect */ return tvb_length(tvb); }
static void rs43(tvbuff_t *tvb, proto_tree *tree) { proto_tree_add_item(tree, hf_ipmi_stor_43_next, tvb, 0, 2, ENC_LITTLE_ENDIAN); proto_tree_add_item(tree, hf_ipmi_stor_43_data, tvb, 2, tvb_length(tvb) - 2, ENC_NA); }
static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *clnp_tree = NULL; proto_item *ti; guint8 cnf_proto_id; guint8 cnf_hdr_len; guint8 cnf_vers; guint8 cnf_ttl; guint8 cnf_type; char flag_string[6+1]; const char *pdu_type_string; proto_tree *type_tree; guint16 segment_length; guint16 du_id = 0; guint16 segment_offset = 0; guint16 cnf_cksum; cksum_status_t cksum_status; int offset; guchar src_len, dst_len, nsel, opt_len = 0; const guint8 *dst_addr, *src_addr; guint next_length; proto_tree *discpdu_tree; gboolean save_in_error_pkt; fragment_data *fd_head; tvbuff_t *next_tvb; gboolean update_col_info = TRUE; gboolean save_fragmented; col_set_str(pinfo->cinfo, COL_PROTOCOL, "CLNP"); col_clear(pinfo->cinfo, COL_INFO); cnf_proto_id = tvb_get_guint8(tvb, P_CLNP_PROTO_ID); if (cnf_proto_id == NLPID_NULL) { col_set_str(pinfo->cinfo, COL_INFO, "Inactive subset"); if (tree) { ti = proto_tree_add_item(tree, proto_clnp, tvb, P_CLNP_PROTO_ID, 1, ENC_NA); clnp_tree = proto_item_add_subtree(ti, ett_clnp); proto_tree_add_uint_format(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1, cnf_proto_id, "Inactive subset"); } next_tvb = tvb_new_subset_remaining(tvb, 1); if (call_dissector(ositp_inactive_handle, next_tvb, pinfo, tree) == 0) call_dissector(data_handle,tvb, pinfo, tree); return; } /* return if version not known */ cnf_vers = tvb_get_guint8(tvb, P_CLNP_VERS); if (cnf_vers != ISO8473_V1) { call_dissector(data_handle,tvb, pinfo, tree); return; } /* fixed part decoding */ cnf_hdr_len = tvb_get_guint8(tvb, P_CLNP_HDR_LEN); opt_len = cnf_hdr_len; if (tree) { ti = proto_tree_add_item(tree, proto_clnp, tvb, 0, cnf_hdr_len, ENC_NA); clnp_tree = proto_item_add_subtree(ti, ett_clnp); proto_tree_add_uint(clnp_tree, hf_clnp_id, tvb, P_CLNP_PROTO_ID, 1, cnf_proto_id); proto_tree_add_uint(clnp_tree, hf_clnp_length, tvb, P_CLNP_HDR_LEN, 1, cnf_hdr_len); proto_tree_add_uint(clnp_tree, hf_clnp_version, tvb, P_CLNP_VERS, 1, cnf_vers); cnf_ttl = tvb_get_guint8(tvb, P_CLNP_TTL); proto_tree_add_uint_format(clnp_tree, hf_clnp_ttl, tvb, P_CLNP_TTL, 1, cnf_ttl, "Holding Time : %u (%u.%u secs)", cnf_ttl, cnf_ttl / 2, (cnf_ttl % 2) * 5); } cnf_type = tvb_get_guint8(tvb, P_CLNP_TYPE); pdu_type_string = val_to_str(cnf_type & CNF_TYPE, npdu_type_abbrev_vals, "Unknown (0x%02x)"); flag_string[0] = '\0'; if (cnf_type & CNF_SEG_OK) g_strlcat(flag_string, "S ", 7); if (cnf_type & CNF_MORE_SEGS) g_strlcat(flag_string, "M ", 7); if (cnf_type & CNF_ERR_OK) g_strlcat(flag_string, "E ", 7); if (tree) { ti = proto_tree_add_uint_format(clnp_tree, hf_clnp_type, tvb, P_CLNP_TYPE, 1, cnf_type, "PDU Type : 0x%02x (%s%s)", cnf_type, flag_string, pdu_type_string); type_tree = proto_item_add_subtree(ti, ett_clnp_type); proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s", decode_boolean_bitfield(cnf_type, CNF_SEG_OK, 8, "Segmentation permitted", "Segmentation not permitted")); proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s", decode_boolean_bitfield(cnf_type, CNF_MORE_SEGS, 8, "More segments", "Last segment")); proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s", decode_boolean_bitfield(cnf_type, CNF_ERR_OK, 8, "Report error if PDU discarded", "Don't report error if PDU discarded")); proto_tree_add_text(type_tree, tvb, P_CLNP_TYPE, 1, "%s", decode_enumerated_bitfield(cnf_type, CNF_TYPE, 8, npdu_type_vals, "%s")); } /* If we don't have the full header - i.e., not enough to see the segmentation part and determine whether this datagram is segmented or not - set the Info column now; we'll get an exception before we set it otherwise. */ if (tvb_length(tvb) < cnf_hdr_len) { col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string); } segment_length = tvb_get_ntohs(tvb, P_CLNP_SEGLEN); cnf_cksum = tvb_get_ntohs(tvb, P_CLNP_CKSUM); cksum_status = calc_checksum(tvb, 0, cnf_hdr_len, cnf_cksum); if (tree) { proto_tree_add_uint(clnp_tree, hf_clnp_pdu_length, tvb, P_CLNP_SEGLEN, 2, segment_length); switch (cksum_status) { default: /* * No checksum present, or not enough of the header present to * checksum it. */ proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb, P_CLNP_CKSUM, 2, cnf_cksum, "Checksum : 0x%04x", cnf_cksum); break; case CKSUM_OK: /* * Checksum is correct. */ proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb, P_CLNP_CKSUM, 2, cnf_cksum, "Checksum : 0x%04x (correct)", cnf_cksum); break; case CKSUM_NOT_OK: /* * Checksum is not correct. */ proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, tvb, P_CLNP_CKSUM, 2, cnf_cksum, "Checksum : 0x%04x (incorrect)", cnf_cksum); break; } opt_len -= 9; /* Fixed part of Hesder */ } /* tree */ /* address part */ offset = P_CLNP_ADDRESS_PART; dst_len = tvb_get_guint8(tvb, offset); dst_addr = tvb_get_ptr(tvb, offset + 1, dst_len); nsel = tvb_get_guint8(tvb, offset + dst_len); src_len = tvb_get_guint8(tvb, offset + dst_len + 1); src_addr = tvb_get_ptr(tvb, offset + dst_len + 2, src_len); if (tree) { proto_tree_add_uint(clnp_tree, hf_clnp_dest_length, tvb, offset, 1, dst_len); proto_tree_add_bytes_format(clnp_tree, hf_clnp_dest, tvb, offset + 1 , dst_len, dst_addr, " DA : %s", print_nsap_net(dst_addr, dst_len)); proto_tree_add_uint(clnp_tree, hf_clnp_src_length, tvb, offset + 1 + dst_len, 1, src_len); proto_tree_add_bytes_format(clnp_tree, hf_clnp_src, tvb, offset + dst_len + 2, src_len, src_addr, " SA : %s", print_nsap_net(src_addr, src_len)); opt_len -= dst_len + src_len +2; } SET_ADDRESS(&pinfo->net_src, AT_OSI, src_len, src_addr); SET_ADDRESS(&pinfo->src, AT_OSI, src_len, src_addr); SET_ADDRESS(&pinfo->net_dst, AT_OSI, dst_len, dst_addr); SET_ADDRESS(&pinfo->dst, AT_OSI, dst_len, dst_addr); /* Segmentation Part */ offset += dst_len + src_len + 2; if (cnf_type & CNF_SEG_OK) { #if 0 struct clnp_segment seg; /* XXX - not used */ tvb_memcpy(tvb, (guint8 *)&seg, offset, sizeof(seg)); /* XXX - not used */ #endif segment_offset = tvb_get_ntohs(tvb, offset + 2); du_id = tvb_get_ntohs(tvb, offset); if (tree) { proto_tree_add_text(clnp_tree, tvb, offset, 2, "Data unit identifier: %06u", du_id); proto_tree_add_text(clnp_tree, tvb, offset + 2 , 2, "Segment offset : %6u", segment_offset); proto_tree_add_text(clnp_tree, tvb, offset + 4 , 2, "Total length : %6u", tvb_get_ntohs(tvb, offset + 4)); } offset += 6; opt_len -= 6; } if (tree) { /* To do : decode options */ #if 0 proto_tree_add_text(clnp_tree, tvb, offset, cnf_hdr_len - offset, "Options/Data: <not shown>"); #endif /* QUICK HACK Option Len:= PDU_Hd_length-( FixedPart+AddresPart+SegmentPart )*/ dissect_osi_options( opt_len, tvb, offset, clnp_tree ); } offset = cnf_hdr_len; /* If clnp_reassemble is on, this is a segment, we have all the * data in the segment, and the checksum is valid, then just add the * segment to the hashtable. */ save_fragmented = pinfo->fragmented; if (clnp_reassemble && (cnf_type & CNF_SEG_OK) && ((cnf_type & CNF_MORE_SEGS) || segment_offset != 0) && tvb_bytes_exist(tvb, offset, segment_length - cnf_hdr_len) && segment_length > cnf_hdr_len && cksum_status != CKSUM_NOT_OK) { fd_head = fragment_add_check(tvb, offset, pinfo, du_id, clnp_segment_table, clnp_reassembled_table, segment_offset, segment_length - cnf_hdr_len, cnf_type & CNF_MORE_SEGS); next_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled CLNP", fd_head, &clnp_frag_items, &update_col_info, clnp_tree); } else { /* If this is the first segment, dissect its contents, otherwise just show it as a segment. XXX - if we eventually don't save the reassembled contents of all segmented datagrams, we may want to always reassemble. */ if ((cnf_type & CNF_SEG_OK) && segment_offset != 0) { /* Not the first segment - don't dissect it. */ next_tvb = NULL; } else { /* First segment, or not segmented. Dissect what we have here. */ /* Get a tvbuff for the payload. */ next_tvb = tvb_new_subset_remaining(tvb, offset); /* * If this is the first segment, but not the only segment, * tell the next protocol that. */ if ((cnf_type & (CNF_SEG_OK|CNF_MORE_SEGS)) == (CNF_SEG_OK|CNF_MORE_SEGS)) pinfo->fragmented = TRUE; else pinfo->fragmented = FALSE; } } if (next_tvb == NULL) { /* Just show this as a segment. */ col_add_fstr(pinfo->cinfo, COL_INFO, "Fragmented %s NPDU %s(off=%u)", pdu_type_string, flag_string, segment_offset); /* As we haven't reassembled anything, we haven't changed "pi", so we don't have to restore it. */ call_dissector(data_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree); pinfo->fragmented = save_fragmented; return; } if (tvb_offset_exists(tvb, offset)) { switch (cnf_type & CNF_TYPE) { case DT_NPDU: case MD_NPDU: /* Continue with COTP if any data. XXX - if this isn't the first Derived PDU of a segmented Initial PDU, skip that? */ if (nsel == (guchar)tp_nsap_selector || always_decode_transport) { if (call_dissector(ositp_handle, next_tvb, pinfo, tree) != 0) { pinfo->fragmented = save_fragmented; return; /* yes, it appears to be COTP or CLTP */ } } if (dissector_try_heuristic(clnp_heur_subdissector_list, next_tvb, pinfo, tree)) { pinfo->fragmented = save_fragmented; return; /* yes, it appears to be one of the protocols in the heuristic list */ } break; case ER_NPDU: /* The payload is the header and "none, some, or all of the data part of the discarded PDU", i.e. it's like an ICMP error; dissect it as a CLNP PDU. */ col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string); next_length = tvb_length_remaining(tvb, offset); if (next_length != 0) { /* We have payload; dissect it. */ ti = proto_tree_add_text(clnp_tree, tvb, offset, next_length, "Discarded PDU"); discpdu_tree = proto_item_add_subtree(ti, ett_clnp_disc_pdu); /* Save the current value of the "we're inside an error packet" flag, and set that flag; subdissectors may treat packets that are the payload of error packets differently from "real" packets. */ save_in_error_pkt = pinfo->flags.in_error_pkt; pinfo->flags.in_error_pkt = TRUE; call_dissector(clnp_handle, next_tvb, pinfo, discpdu_tree); /* Restore the "we're inside an error packet" flag. */ pinfo->flags.in_error_pkt = save_in_error_pkt; } pinfo->fragmented = save_fragmented; return; /* we're done with this PDU */ case ERQ_NPDU: case ERP_NPDU: /* XXX - dissect this */ break; } } col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string); call_dissector(data_handle,next_tvb, pinfo, tree); pinfo->fragmented = save_fragmented; } /* dissect_clnp */
static void rq44(tvbuff_t *tvb, proto_tree *tree) { proto_tree_add_item(tree, hf_ipmi_stor_44_data, tvb, 0, tvb_length(tvb), ENC_NA); }
/*FUNCTION:------------------------------------------------------ * NAME * dissect_zbee_secure * DESCRIPTION * Dissects and decrypts secured ZigBee frames. * * Will return a valid tvbuff only if security processing was * successful. If processing fails, then this function will * handle internally and return NULL. * PARAMETERS * tvbuff_t *tvb - pointer to buffer containing raw packet. * packet_info *pinfo - pointer to packet information fields * proto_tree *tree - pointer to data tree Wireshark uses to display packet. * guint offset - pointer to the start of the auxilliary security header. * guint64 src64 - extended source address, or 0 if unknown. * RETURNS * tvbuff_t * *--------------------------------------------------------------- */ tvbuff_t * dissect_zbee_secure(tvbuff_t *tvb, packet_info *pinfo, proto_tree* tree, guint offset) { proto_tree *sec_tree = NULL; proto_item *sec_root; proto_tree *field_tree; proto_item *ti; zbee_security_packet packet; guint mic_len; gint payload_len; tvbuff_t *payload_tvb; #ifdef HAVE_LIBGCRYPT guint8 *enc_buffer; guint8 *dec_buffer; gboolean decrypted; GSList **nwk_keyring; GSList *GSList_i; key_record_t *key_rec = NULL; #endif zbee_nwk_hints_t *nwk_hints; ieee802154_hints_t *ieee_hints; ieee802154_map_rec *map_rec = NULL; /* Init */ memset(&packet, 0, sizeof(zbee_security_packet)); /* Get pointers to any useful frame data from lower layers */ nwk_hints = (zbee_nwk_hints_t *)p_get_proto_data(pinfo->fd, proto_get_id_by_filter_name(ZBEE_PROTOABBREV_NWK)); ieee_hints = (ieee802154_hints_t *)p_get_proto_data(pinfo->fd, proto_get_id_by_filter_name(IEEE802154_PROTOABBREV_WPAN)); /* Create a subtree for the security information. */ if (tree) { sec_root = proto_tree_add_text(tree, tvb, offset, tvb_length_remaining(tvb, offset), "ZigBee Security Header"); sec_tree = proto_item_add_subtree(sec_root, ett_zbee_sec); } /* Get and display the Security control field */ packet.control = tvb_get_guint8(tvb, offset); /* Patch the security level. */ packet.control &= ~ZBEE_SEC_CONTROL_LEVEL; packet.control |= (ZBEE_SEC_CONTROL_LEVEL & gPREF_zbee_sec_level); /* * Eww, I think I just threw up a little... ZigBee requires this field * to be patched before computing the MIC, but we don't have write-access * to the tvbuff. So we need to allocate a copy of the whole thing just * so we can fix these 3 bits. Memory allocated by ep_tvb_memdup() is * automatically freed before the next packet is processed. */ #ifdef HAVE_LIBGCRYPT enc_buffer = (guint8 *)ep_tvb_memdup(tvb, 0, tvb_length(tvb)); /* * Override the const qualifiers and patch the security level field, we * know it is safe to overide the const qualifiers because we just * allocated this memory via ep_tvb_memdup(). */ enc_buffer[offset] = packet.control; #endif /* HAVE_LIBGCRYPT */ packet.level = zbee_get_bit_field(packet.control, ZBEE_SEC_CONTROL_LEVEL); packet.key_id = zbee_get_bit_field(packet.control, ZBEE_SEC_CONTROL_KEY); packet.nonce = zbee_get_bit_field(packet.control, ZBEE_SEC_CONTROL_NONCE); if (tree) { ti = proto_tree_add_text(sec_tree, tvb, offset, 1, "Security Control Field"); field_tree = proto_item_add_subtree(ti, ett_zbee_sec_control); proto_tree_add_uint(field_tree, hf_zbee_sec_key_id, tvb, offset, 1, packet.control & ZBEE_SEC_CONTROL_KEY); proto_tree_add_boolean(field_tree, hf_zbee_sec_nonce, tvb, offset, 1, packet.control & ZBEE_SEC_CONTROL_NONCE); } offset += 1; /* Get and display the frame counter field. */ packet.counter = tvb_get_letohl(tvb, offset); if (tree) { proto_tree_add_uint(sec_tree, hf_zbee_sec_counter, tvb, offset, 4, packet.counter); } offset += 4; if (packet.nonce) { /* Get and display the source address of the device that secured this payload. */ packet.src64 = tvb_get_letoh64(tvb, offset); if (tree) { proto_tree_add_item(sec_tree, hf_zbee_sec_src64, tvb, offset, 8, ENC_LITTLE_ENDIAN); } #if 1 if (!pinfo->fd->flags.visited) { switch ( packet.key_id ) { case ZBEE_SEC_KEY_LINK: if (nwk_hints) { /* Map this long address with the nwk layer short address. */ nwk_hints->map_rec = ieee802154_addr_update(&zbee_nwk_map, nwk_hints->src, ieee_hints->src_pan, packet.src64, pinfo->current_proto, pinfo->fd->num); } break; case ZBEE_SEC_KEY_NWK: if (ieee_hints) { /* Map this long address with the ieee short address. */ ieee_hints->map_rec = ieee802154_addr_update(&zbee_nwk_map, ieee_hints->src16, ieee_hints->src_pan, packet.src64, pinfo->current_proto, pinfo->fd->num); } break; /* We ignore the extended source addresses used to encrypt payloads with these * types of keys, because they can emerge from APS tunnels created by nodes whose * short address is not recorded in the packet. */ case ZBEE_SEC_KEY_TRANSPORT: case ZBEE_SEC_KEY_LOAD: break; } } #endif offset += 8; } else { /* Look for a source address in hints */ switch ( packet.key_id ) { case ZBEE_SEC_KEY_NWK: /* use the ieee extended source address for NWK decryption */ if ( ieee_hints && (map_rec = ieee_hints->map_rec) ) packet.src64 = map_rec->addr64; else if (tree) proto_tree_add_text(sec_tree, tvb, 0, 0, "[Extended Source: Unknown]"); break; default: /* use the nwk extended source address for APS decryption */ if ( nwk_hints && (map_rec = nwk_hints->map_rec) ) packet.src64 = map_rec->addr64; else if (tree) proto_tree_add_text(sec_tree, tvb, 0, 0, "[Extended Source: Unknown]"); break; } } if (packet.key_id == ZBEE_SEC_KEY_NWK) { /* Get and display the key sequence number. */ packet.key_seqno = tvb_get_guint8(tvb, offset); if (tree) { proto_tree_add_uint(sec_tree, hf_zbee_sec_key_seqno, tvb, offset, 1, packet.key_seqno); } offset += 1; } /* Determine the length of the MIC. */ switch (packet.level) { case ZBEE_SEC_ENC: case ZBEE_SEC_NONE: default: mic_len=0; break; case ZBEE_SEC_ENC_MIC32: case ZBEE_SEC_MIC32: mic_len=4; break; case ZBEE_SEC_ENC_MIC64: case ZBEE_SEC_MIC64: mic_len=8; break; case ZBEE_SEC_ENC_MIC128: case ZBEE_SEC_MIC128: mic_len=16; break; } /* switch */ /* Get and display the MIC. */ if (mic_len) { /* Display the MIC. */ if (tree) { proto_tree_add_item(sec_tree, hf_zbee_sec_mic, tvb, (gint)(tvb_length(tvb)-mic_len), mic_len, ENC_NA); } } /* Check for null payload. */ if ( !(payload_len = tvb_reported_length_remaining(tvb, offset+mic_len)) ) { return NULL; } else if ( payload_len < 0 ) { THROW(ReportedBoundsError); } /********************************************** * Perform Security Operations on the Frame * ********************************************** */ if ((packet.level == ZBEE_SEC_NONE) || (packet.level == ZBEE_SEC_MIC32) || (packet.level == ZBEE_SEC_MIC64) || (packet.level == ZBEE_SEC_MIC128)) { /* Payload is only integrity protected. Just return the sub-tvbuff. */ return tvb_new_subset(tvb, offset, payload_len, payload_len); } #ifdef HAVE_LIBGCRYPT /* Allocate memory to decrypt the payload into. */ dec_buffer = (guint8 *)g_malloc(payload_len); decrypted = FALSE; if ( packet.src64 ) { if (pinfo->fd->flags.visited) { if ( nwk_hints ) { /* Use previously found key */ switch ( packet.key_id ) { case ZBEE_SEC_KEY_NWK: if ( (key_rec = nwk_hints->nwk) ) { decrypted = zbee_sec_decrypt_payload( &packet, enc_buffer, offset, dec_buffer, payload_len, mic_len, nwk_hints->nwk->key); } break; default: if ( (key_rec = nwk_hints->link) ) { decrypted = zbee_sec_decrypt_payload( &packet, enc_buffer, offset, dec_buffer, payload_len, mic_len, nwk_hints->link->key); } break; } } } /* ( !pinfo->fd->flags.visited ) */ else { /* We only search for sniffed keys in the first pass, * to save time, and because decrypting with keys * transported in future packets is cheating */ /* Lookup NWK and link key in hash for this pan. */ /* This overkill approach is a placeholder for a hash that looks up * a key ring for a link key associated with a pair of devices. */ if ( nwk_hints ) { nwk_keyring = (GSList **)g_hash_table_lookup(zbee_table_nwk_keyring, &nwk_hints->src_pan); if ( nwk_keyring ) { GSList_i = *nwk_keyring; while ( GSList_i && !decrypted ) { decrypted = zbee_sec_decrypt_payload( &packet, enc_buffer, offset, dec_buffer, payload_len, mic_len, ((key_record_t *)(GSList_i->data))->key); if (decrypted) { /* save pointer to the successful key record */ switch (packet.key_id) { case ZBEE_SEC_KEY_NWK: key_rec = nwk_hints->nwk = (key_record_t *)(GSList_i->data); break; default: key_rec = nwk_hints->link = (key_record_t *)(GSList_i->data); break; } } else { GSList_i = g_slist_next(GSList_i); } } } /* Loop through user's password table for preconfigured keys, our last resort */ GSList_i = zbee_pc_keyring; while ( GSList_i && !decrypted ) { decrypted = zbee_sec_decrypt_payload( &packet, enc_buffer, offset, dec_buffer, payload_len, mic_len, ((key_record_t *)(GSList_i->data))->key); if (decrypted) { /* save pointer to the successful key record */ switch (packet.key_id) { case ZBEE_SEC_KEY_NWK: key_rec = nwk_hints->nwk = (key_record_t *)(GSList_i->data); break; default: key_rec = nwk_hints->link = (key_record_t *)(GSList_i->data); break; } } else { GSList_i = g_slist_next(GSList_i); } } } } /* ( ! pinfo->fd->flags.visited ) */ } /* ( packet.src64 ) */ if ( decrypted ) { if ( tree && key_rec ) { if ( key_rec->frame_num == ZBEE_SEC_PC_KEY ) { ti = proto_tree_add_text(sec_tree, tvb, 0, 0, "Decryption Key: %s", key_rec->label); } else { ti = proto_tree_add_uint(sec_tree, hf_zbee_sec_key_origin, tvb, 0, 0, key_rec->frame_num); } PROTO_ITEM_SET_GENERATED(ti); } /* Found a key that worked, setup the new tvbuff_t and return */ payload_tvb = tvb_new_child_real_data(tvb, dec_buffer, payload_len, payload_len); tvb_set_free_cb(payload_tvb, g_free); /* set up callback to free dec_buffer */ add_new_data_source(pinfo, payload_tvb, "Decrypted ZigBee Payload"); /* Done! */ return payload_tvb; } g_free(dec_buffer); #endif /* HAVE_LIBGCRYPT */ /* Add expert info. */ expert_add_info_format(pinfo, sec_tree, PI_UNDECODED, PI_WARN, "Encrypted Payload"); /* Create a buffer for the undecrypted payload. */ payload_tvb = tvb_new_subset(tvb, offset, payload_len, -1); /* Dump the payload to the data dissector. */ call_dissector(data_handle, payload_tvb, pinfo, tree); /* Couldn't decrypt, so return NULL. */ return NULL; } /* dissect_zbee_secure */
static void dissect_lapdm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *lapdm_tree, *addr_tree, *length_tree; proto_item *lapdm_ti, *addr_ti, *length_ti; guint8 addr, length, cr, sapi, len/*, n_s*/; int control; gboolean m; tvbuff_t *payload; int available_length; gboolean is_response = FALSE; /* Check that there's enough data */ if (tvb_length(tvb) < LAPDM_HEADER_LEN) return; col_set_str(pinfo->cinfo, COL_PROTOCOL, "LAPDm"); addr = tvb_get_guint8(tvb, 0); length = tvb_get_guint8(tvb, 2); cr = addr & LAPDM_CR; if (pinfo->p2p_dir == P2P_DIR_RECV) { is_response = cr ? FALSE : TRUE; } else if (pinfo->p2p_dir == P2P_DIR_SENT) { is_response = cr ? TRUE : FALSE; } if (tree) { lapdm_ti = proto_tree_add_item(tree, proto_lapdm, tvb, 0, LAPDM_HEADER_LEN, ENC_NA); lapdm_tree = proto_item_add_subtree(lapdm_ti, ett_lapdm); addr_ti = proto_tree_add_uint(lapdm_tree, hf_lapdm_address, tvb, 0, 1, addr); addr_tree = proto_item_add_subtree(addr_ti, ett_lapdm_address); proto_tree_add_uint(addr_tree, hf_lapdm_lpd, tvb, 0, 1, addr); proto_tree_add_uint(addr_tree, hf_lapdm_sapi, tvb, 0, 1, addr); proto_tree_add_uint(addr_tree, hf_lapdm_cr, tvb, 0, 1, addr); proto_tree_add_uint(addr_tree, hf_lapdm_ea, tvb, 0, 1, addr); } else { lapdm_ti = NULL; lapdm_tree = NULL; } control = dissect_xdlc_control(tvb, 1, pinfo, lapdm_tree, hf_lapdm_control, ett_lapdm_control, &lapdm_cf_items, NULL /* LAPDm doesnt support extended */, NULL, NULL, is_response, FALSE, FALSE); if (tree) { length_ti = proto_tree_add_uint(lapdm_tree, hf_lapdm_length, tvb, 2, 1, length); length_tree = proto_item_add_subtree(length_ti, ett_lapdm_length); proto_tree_add_uint(length_tree, hf_lapdm_len, tvb, 2, 1, length); proto_tree_add_uint(length_tree, hf_lapdm_m, tvb, 2, 1, length); proto_tree_add_uint(length_tree, hf_lapdm_el, tvb, 2, 1, length); } sapi = (addr & LAPDM_SAPI) >> LAPDM_SAPI_SHIFT; len = (length & LAPDM_LEN) >> LAPDM_LEN_SHIFT; /*n_s = (control & XDLC_N_S_MASK) >> XDLC_N_S_SHIFT;*/ m = (length & LAPDM_M) >> LAPDM_M_SHIFT; available_length = tvb_length(tvb) - LAPDM_HEADER_LEN; /* No point in doing anything if no payload */ if( !MIN(len, available_length) ) return; payload = tvb_new_subset(tvb, LAPDM_HEADER_LEN, MIN(len,available_length), -1); /* Potentially segmented I frame */ if( (control & XDLC_I_MASK) == XDLC_I && reassemble_lapdm ) { fragment_head *fd_m = NULL; tvbuff_t *reassembled = NULL; guint32 fragment_id; gboolean save_fragmented = pinfo->fragmented; pinfo->fragmented = m; /* Rely on caller to provide a way to group fragments */ fragment_id = (pinfo->circuit_id << 4) | (sapi << 1) | pinfo->p2p_dir; /* This doesn't seem the best way of doing it as doesn't take N(S) into account, but N(S) isn't always 0 for the first fragment! */ fd_m = fragment_add_seq_next (&lapdm_reassembly_table, payload, 0, pinfo, fragment_id, /* guint32 ID for fragments belonging together */ NULL, /*n_s guint32 fragment sequence number */ len, /* guint32 fragment length */ m); /* More fragments? */ reassembled = process_reassembled_data(payload, 0, pinfo, "Reassembled LAPDm", fd_m, &lapdm_frag_items, NULL, lapdm_tree); /* Reassembled into this packet */ if (fd_m && pinfo->fd->num == fd_m->reassembled_in) { if (!dissector_try_uint(lapdm_sapi_dissector_table, sapi, reassembled, pinfo, tree)) call_dissector(data_handle, reassembled, pinfo, tree); } else { col_append_str(pinfo->cinfo, COL_INFO, " (Fragment)"); if (tree) { proto_tree_add_text(lapdm_tree, payload, 0, -1, "Fragment Data"); } } /* Now reset fragmentation information in pinfo */ pinfo->fragmented = save_fragmented; } else { /* Whole packet If we have some data, try and dissect it (only happens for UI, SABM, UA or I frames) */ if (!dissector_try_uint(lapdm_sapi_dissector_table, sapi, payload, pinfo, tree)) call_dissector(data_handle,payload, pinfo, tree); } }
static gint ett_miop = -1; #define MIOP_MAGIC "MIOP" static void dissect_miop (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree); static gboolean dissect_miop_heur (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, void * data _U_) { guint tot_len; /* check magic number and version */ tot_len = tvb_length(tvb); if (tot_len < MIOP_HEADER_SIZE) /* tot_len < 16 */ { /* Not enough data captured to hold the GIOP header; don't try to interpret it as GIOP. */ return FALSE; } if ( tvb_memeql(tvb, 0, MIOP_MAGIC ,4) != 0) return FALSE; if (pinfo->ptype != PT_UDP) return FALSE; dissect_miop (tvb, pinfo, tree);
guint32 start_off) { guint32 offset; offset = start_off; /* AuthScheme */ proto_tree_add_item(tree, hf_negoex_authscheme, tvb, offset, 16, ENC_LITTLE_ENDIAN); offset += 16; /* ErrorCode, an NTSTATUS :-) */ proto_tree_add_item(tree, hf_negoex_errorcode, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; /* The rest */ proto_tree_add_text(tree, tvb, offset, tvb_length(tvb) - offset, "The rest of the alert message"); } static void dissect_negoex_verify_message(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint32 start_off) { guint32 offset; guint32 checksum_vector_offset; guint32 checksum_vector_count; proto_item *pi; proto_tree *checksum;
/* This function will try to determine the complete size of a PDU * based on the information in the header. */ static guint get_nbd_tcp_pdu_len(packet_info *pinfo, tvbuff_t *tvb, int offset) { guint32 magic, type, packet; conversation_t *conversation; nbd_conv_info_t *nbd_info; nbd_transaction_t *nbd_trans=NULL; wmem_tree_key_t hkey[3]; guint32 handle[2]; magic=tvb_get_ntohl(tvb, offset); switch(magic){ case NBD_REQUEST_MAGIC: type=tvb_get_ntohl(tvb, offset+4); switch(type){ case NBD_CMD_WRITE: return tvb_get_ntohl(tvb, offset+24)+28; default: return 28; } case NBD_RESPONSE_MAGIC: /* * Do we have a conversation for this connection? */ conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); if (conversation == NULL) { /* No, so just return the rest of the current packet */ return tvb_length(tvb); } /* * Do we have a state structure for this conv */ nbd_info = (nbd_conv_info_t *)conversation_get_proto_data(conversation, proto_nbd); if (!nbd_info) { /* No, so just return the rest of the current packet */ return tvb_length(tvb); } if(!pinfo->fd->flags.visited){ /* * Do we have a state structure for this transaction */ handle[0]=tvb_get_ntohl(tvb, offset+8); handle[1]=tvb_get_ntohl(tvb, offset+12); hkey[0].length=2; hkey[0].key=handle; hkey[1].length=0; nbd_trans=(nbd_transaction_t *)wmem_tree_lookup32_array(nbd_info->unacked_pdus, hkey); if(!nbd_trans){ /* No, so just return the rest of the current packet */ return tvb_length(tvb); } } else { /* * Do we have a state structure for this transaction */ handle[0]=tvb_get_ntohl(tvb, offset+8); handle[1]=tvb_get_ntohl(tvb, offset+12); packet=pinfo->fd->num; hkey[0].length=1; hkey[0].key=&packet; hkey[1].length=2; hkey[1].key=handle; hkey[2].length=0; nbd_trans=(nbd_transaction_t *)wmem_tree_lookup32_array(nbd_info->acked_pdus, hkey); if(!nbd_trans){ /* No, so just return the rest of the current packet */ return tvb_length(tvb); } } /* If this is a read response we must add the datalen to * the pdu size */ if(nbd_trans->type==NBD_CMD_READ){ return 16+nbd_trans->datalen; } else { return 16; } default: break; } /* Did not really look like a NBD packet after all */ return 0; }
} static int dissect_dlm3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void *data _U_) { proto_item *item, *sub_item; proto_tree *tree, *sub_tree; int offset; guint length; guint32 h_version; guint8 h_cmd; /* Check that there's enough data */ length = tvb_length(tvb); if (length < 4 + 4 + 4 + 2 + 1 + 1) return 0; /* Check the protocol version */ h_version = tvb_get_letohl(tvb, 0); if (h_version != (DLM3_MAJOR_VERSION|DLM3_MINOR_VERSION)) return 0; /* Check the command */ h_cmd = tvb_get_guint8(tvb, 4 + 4 + 4 + 2) ; if ((h_cmd != DLM3_MSG) && (h_cmd != DLM3_RCOM)) return 0; if ((h_cmd == DLM3_MSG) && (length < ((4 + 4 + 4 + 2 + 1 + 1) + (4 * 12 + 4 * 6))))
static int dissect_ProtocolExtensionFieldExtensionValue(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { return (dissector_try_uint(sbc_ap_extension_dissector_table, ProtocolExtensionID, tvb, pinfo, tree)) ? tvb_length(tvb) : 0; }
#include "ui/gtk/follow_stream.h" #include "ui/gtk/keys.h" #include "ui/gtk/main.h" #include "ui/gtk/follow_udp.h" static int udp_queue_packet_data(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data) { follow_record_t *follow_record; follow_info_t *follow_info = (follow_info_t *)tapdata; tvbuff_t *next_tvb = (tvbuff_t *)data; follow_record = g_new(follow_record_t,1); follow_record->data = g_byte_array_sized_new(tvb_length(next_tvb)); follow_record->data = g_byte_array_append(follow_record->data, tvb_get_ptr(next_tvb, 0, -1), tvb_length(next_tvb)); if (follow_info->client_port == 0) { follow_info->client_port = pinfo->srcport; COPY_ADDRESS(&follow_info->client_ip, &pinfo->src); } if (ADDRESSES_EQUAL(&follow_info->client_ip, &pinfo->src) && follow_info->client_port == pinfo->srcport) follow_record->is_server = FALSE; else follow_record->is_server = TRUE; /* update stream counter */
static int dissect_SuccessfulOutcomeValue(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { return (dissector_try_uint(sbc_ap_proc_sout_dissector_table, ProcedureCode, tvb, pinfo, tree)) ? tvb_length(tvb) : 0; }
/* Code to actually dissect the packets */ static int dissect_lisp_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { gint offset = 0; guint8 flags; guint8 ip_ver; tvbuff_t *next_tvb; proto_item *ti; proto_item *tif; proto_tree *lisp_data_tree; proto_tree *lisp_data_flags_tree; /* Check that there's enough data */ if (tvb_length(tvb) < LISP_DATA_HEADER_LEN) return 0; /* Make entries in Protocol column and Info column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "LISP"); col_set_str(pinfo->cinfo, COL_INFO, "LISP Encapsulation Header"); if (tree) { /* create display subtree for the protocol */ ti = proto_tree_add_item(tree, proto_lisp_data, tvb, 0, LISP_DATA_HEADER_LEN, ENC_NA); lisp_data_tree = proto_item_add_subtree(ti, ett_lisp_data); tif = proto_tree_add_item(lisp_data_tree, hf_lisp_data_flags, tvb, offset, 1, ENC_BIG_ENDIAN); lisp_data_flags_tree = proto_item_add_subtree(tif, ett_lisp_data_flags); proto_tree_add_item(lisp_data_flags_tree, hf_lisp_data_flags_nonce, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(lisp_data_flags_tree, hf_lisp_data_flags_lsb, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(lisp_data_flags_tree, hf_lisp_data_flags_enr, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(lisp_data_flags_tree, hf_lisp_data_flags_mv, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(lisp_data_flags_tree, hf_lisp_data_flags_iid, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(lisp_data_flags_tree, hf_lisp_data_flags_res, tvb, offset, 1, ENC_BIG_ENDIAN); flags = tvb_get_guint8(tvb, offset); offset += 1; if (flags&LISP_DATA_FLAG_E && !(flags&LISP_DATA_FLAG_N)) { proto_tree_add_text(lisp_data_tree, tvb, offset, 0, "Invalid flag combination: if E is set, N MUST be set"); } if (flags&LISP_DATA_FLAG_N) { if (flags&LISP_DATA_FLAG_V) { proto_tree_add_text(lisp_data_tree, tvb, offset, 0, "Invalid flag combination: N and V can't be set both"); } proto_tree_add_item(lisp_data_tree, hf_lisp_data_nonce, tvb, offset, 3, ENC_BIG_ENDIAN); } else { if (flags&LISP_DATA_FLAG_V) { proto_item *tiv; proto_tree *lisp_data_mapver_tree; tiv = proto_tree_add_item(lisp_data_tree, hf_lisp_data_mapver, tvb, offset, 3, ENC_BIG_ENDIAN); lisp_data_mapver_tree = proto_item_add_subtree(tiv, ett_lisp_data_mapver); proto_tree_add_item(lisp_data_mapver_tree, hf_lisp_data_srcmapver, tvb, offset, 3, ENC_BIG_ENDIAN); proto_tree_add_item(lisp_data_mapver_tree, hf_lisp_data_dstmapver, tvb, offset, 3, ENC_BIG_ENDIAN); } } offset += 3; if (flags&LISP_DATA_FLAG_I) { proto_tree_add_item(lisp_data_tree, hf_lisp_data_iid, tvb, offset, 3, ENC_BIG_ENDIAN); offset += 3; if (flags&LISP_DATA_FLAG_L) { proto_tree_add_item(lisp_data_tree, hf_lisp_data_lsb8, tvb, offset, 1, ENC_BIG_ENDIAN); } offset +=1; } else { if (flags&LISP_DATA_FLAG_L) { proto_tree_add_item(lisp_data_tree, hf_lisp_data_lsb, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; } } } /* Check if there is stuff left in the buffer, and return if not */ /* Determine if encapsulated packet is IPv4 or IPv6, and call dissector */ next_tvb = tvb_new_subset_remaining(tvb, LISP_DATA_HEADER_LEN); ip_ver = tvb_get_bits8(next_tvb, 0, 4); switch (ip_ver) { case 4: call_dissector(ipv4_handle, next_tvb, pinfo, tree); break; case 6: call_dissector(ipv6_handle, next_tvb, pinfo, tree); break; default: call_dissector(data_handle, next_tvb, pinfo, tree); break; } /* Return the amount of data this dissector was able to dissect */ return tvb_length(tvb); }