Example #1
0
/* Parsing something like
 * <rawMsg
 *   protocol="Diameter"
 *   version="1">
 *    [truncated]010001244000012C01000...
 * </rawMsg>
 */
static wtap_open_return_val
write_packet_data(wtap_dumper *wdh, wtap_rec *rec, int *err, gchar **err_info, guint8 *file_buf, time_t start_time, int ms, exported_pdu_info_t *exported_pdu_info, char name_str[64])
{
	char *curr_pos, *next_pos;
	char proto_name_str[16];
	char dissector_table_str[32];
	int dissector_table_val=0;
	int tag_str_len = 0;
	int proto_str_len, dissector_table_str_len, raw_data_len, pkt_data_len,  exp_pdu_tags_len, i, j;
	guint8 *packet_buf;
	gchar chr;
	gint val1, val2;
	gboolean port_type_defined = FALSE;
	gboolean use_proto_table = FALSE;

	memset(proto_name_str, 0, sizeof(proto_name_str));
	/* Extract the protocol name */
	curr_pos = strstr(file_buf, "protocol=\"");
	if (!curr_pos){
		return WTAP_OPEN_ERROR;
	}
	curr_pos = curr_pos + 10;
	next_pos = strstr(curr_pos, "\"");
	proto_str_len = (int)(next_pos - curr_pos);
	if (proto_str_len > 15){
		return WTAP_OPEN_ERROR;
	}

	g_strlcpy(proto_name_str, curr_pos, proto_str_len+1);
	ascii_strdown_inplace(proto_name_str);

	/* Do string matching and replace with Wiresharks protocol name */
	if (strcmp(proto_name_str, "gtpv2-c") == 0){
		/* Change to gtpv2 */
		proto_name_str[5] = '\0';
		proto_str_len = 5;
	}
	/* XXX Do we need to check for function="S1" */
	if (strcmp(proto_name_str, "nas") == 0){
		/* Change to nas-eps_plain */
		g_strlcpy(proto_name_str, "nas-eps_plain", 14);
		proto_str_len = 13;
	}
	if (strcmp(proto_name_str, "map") == 0) {
		/* For /GSM) map, it looks like the message data is stored like SendAuthenticationInfoArg
		 * use the GSM MAP dissector table to dissect the content.
		 */
		exported_pdu_info->proto_col_str = g_strdup("GSM MAP");

		if (strcmp(name_str, "sai_request") == 0) {
			use_proto_table = TRUE;
			g_strlcpy(dissector_table_str, "gsm_map.v3.arg.opcode", 22);
			dissector_table_str_len = 21;
			dissector_table_val = 56;
			exported_pdu_info->precense_flags = exported_pdu_info->precense_flags + EXP_PDU_TAG_COL_PROT_BIT;
		}
		else if (strcmp(name_str, "sai_response") == 0) {
			use_proto_table = TRUE;
			g_strlcpy(dissector_table_str, "gsm_map.v3.res.opcode", 22);
			dissector_table_str_len = 21;
			dissector_table_val = 56;
			exported_pdu_info->precense_flags = exported_pdu_info->precense_flags + EXP_PDU_TAG_COL_PROT_BIT;
		} else {
			g_free(exported_pdu_info->proto_col_str);
			exported_pdu_info->proto_col_str = NULL;
		}
	}
	/* Find the start of the raw data*/
	curr_pos = strstr(next_pos, ">") + 1;
	next_pos = strstr(next_pos, "<");

	raw_data_len = (int)(next_pos - curr_pos);

	/* Calculate the space needed for exp pdu tags*/
	if (use_proto_table == FALSE) {
		tag_str_len = (proto_str_len + 3) & 0xfffffffc;
		exp_pdu_tags_len = tag_str_len + 4;
	} else {
		tag_str_len = (dissector_table_str_len + 3) & 0xfffffffc;
		exp_pdu_tags_len = tag_str_len + 4;
		/* Add EXP_PDU_TAG_DISSECTOR_TABLE_NAME_NUM_VAL + length*/
		exp_pdu_tags_len = exp_pdu_tags_len + 4 + 4;
	}

	if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_COL_PROT_BIT) == EXP_PDU_TAG_COL_PROT_BIT) {
		/* The assert prevents static code analyzers to raise warnings */
		g_assert(exported_pdu_info->proto_col_str);
		exp_pdu_tags_len += 4 + (int)strlen(exported_pdu_info->proto_col_str);
	}

	if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_IP_SRC_BIT) == EXP_PDU_TAG_IP_SRC_BIT) {
		exp_pdu_tags_len += 4 + EXP_PDU_TAG_IPV4_SRC_LEN;
	}

	if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_IP6_SRC_BIT) == EXP_PDU_TAG_IP6_SRC_BIT) {
		exp_pdu_tags_len += 4 + EXP_PDU_TAG_IPV6_LEN;
	}

	if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_SRC_PORT_BIT) == EXP_PDU_TAG_SRC_PORT_BIT) {
		if (!port_type_defined) {
			exp_pdu_tags_len += 4 + EXP_PDU_TAG_PORT_TYPE_LEN;
			port_type_defined = TRUE;
		}
		exp_pdu_tags_len += 4 + EXP_PDU_TAG_SRC_PORT_LEN;
	}

	if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_IP_DST_BIT) == EXP_PDU_TAG_IP_DST_BIT) {
		exp_pdu_tags_len += 4 + EXP_PDU_TAG_IPV4_DST_LEN;
	}

	if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_IP6_DST_BIT) == EXP_PDU_TAG_IP6_DST_BIT) {
		exp_pdu_tags_len += 4 + EXP_PDU_TAG_IPV6_LEN;
	}

	if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_DST_PORT_BIT) == EXP_PDU_TAG_DST_PORT_BIT) {
		if (!port_type_defined) {
			exp_pdu_tags_len += 4 + EXP_PDU_TAG_PORT_TYPE_LEN;
		}
		exp_pdu_tags_len += 4 + EXP_PDU_TAG_SRC_PORT_LEN;
	}

	port_type_defined = FALSE;

	/* Allocate the packet buf */
	pkt_data_len = raw_data_len / 2;
	packet_buf = (guint8 *)g_malloc0(pkt_data_len + exp_pdu_tags_len +4);

	/* Fill packet buff */
	if (use_proto_table == FALSE) {
		packet_buf[0] = 0;
		packet_buf[1] = 12; /* EXP_PDU_TAG_PROTO_NAME */
		packet_buf[2] = 0;
		packet_buf[3] = tag_str_len;
		memcpy(&packet_buf[4], proto_name_str, proto_str_len);
		i = 4 + tag_str_len;
	}else{
		packet_buf[0] = 0;
		packet_buf[1] = 14; /* EXP_PDU_TAG_DISSECTOR_TABLE_NAME */
		packet_buf[2] = 0;
		packet_buf[3] = tag_str_len;
		memcpy(&packet_buf[4], dissector_table_str, dissector_table_str_len);
		i = 4 + tag_str_len;
		packet_buf[i] = 0;
		i++;
		packet_buf[i] = EXP_PDU_TAG_DISSECTOR_TABLE_NAME_NUM_VAL;
		i++;
		packet_buf[i] = 0;
		i++;
		packet_buf[i] = 4; /* tag length */;
		i++;
		packet_buf[i] = 0;
		i++;
		packet_buf[i] = 0;
		i++;
		packet_buf[i] = 0;
		i++;
		packet_buf[i] = dissector_table_val;
		i++;
	}

	if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_COL_PROT_BIT) == EXP_PDU_TAG_COL_PROT_BIT) {
		packet_buf[i] = 0;
		i++;
		packet_buf[i] = EXP_PDU_TAG_COL_PROT_TEXT;
		i++;
		packet_buf[i] = 0;
		i++;
		packet_buf[i] = (guint8)strlen(exported_pdu_info->proto_col_str);
		i++;
		for (j = 0; j < (int)strlen(exported_pdu_info->proto_col_str); i++, j++) {
			packet_buf[i] = exported_pdu_info->proto_col_str[j];
		}
		g_free(exported_pdu_info->proto_col_str);
	}


	if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_IP_SRC_BIT) == EXP_PDU_TAG_IP_SRC_BIT) {
		packet_buf[i] = 0;
		i++;
		packet_buf[i] = EXP_PDU_TAG_IPV4_SRC;
		i++;
		packet_buf[i] = 0;
		i++;
		packet_buf[i] = EXP_PDU_TAG_IPV4_SRC_LEN; /* tag length */;
		i++;
		memcpy(packet_buf+i, exported_pdu_info->src_ip, EXP_PDU_TAG_IPV4_SRC_LEN);
		i += EXP_PDU_TAG_IPV4_SRC_LEN;
	}

	if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_IP6_SRC_BIT) == EXP_PDU_TAG_IP6_SRC_BIT) {
		packet_buf[i] = 0;
		i++;
		packet_buf[i] = EXP_PDU_TAG_IPV6_SRC;
		i++;
		packet_buf[i] = 0;
		i++;
		packet_buf[i] = EXP_PDU_TAG_IPV6_LEN; /* tag length */;
		i++;
		memcpy(packet_buf+i, exported_pdu_info->src_ip, EXP_PDU_TAG_IPV6_LEN);
		i += EXP_PDU_TAG_IPV6_LEN;
	}

	if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_SRC_PORT_BIT) == EXP_PDU_TAG_SRC_PORT_BIT) {
		if (!port_type_defined) {
			port_type_defined = TRUE;
			packet_buf[i] = 0;
			i++;
			packet_buf[i] = EXP_PDU_TAG_PORT_TYPE;
			i++;
			packet_buf[i] = 0;
			i++;
			packet_buf[i] = EXP_PDU_TAG_PORT_TYPE_LEN; /* tag length */;
			i++;
			packet_buf[i] = (exported_pdu_info->ptype & 0xff000000) >> 24;
			i++;
			packet_buf[i] = (exported_pdu_info->ptype & 0x00ff0000) >> 16;
			i++;
			packet_buf[i] = (exported_pdu_info->ptype & 0x0000ff00) >> 8;
			i++;
			packet_buf[i] = (exported_pdu_info->ptype & 0x000000ff);
			i++;
		}
		packet_buf[i] = 0;
		i++;
		packet_buf[i] = EXP_PDU_TAG_SRC_PORT;
		i++;
		packet_buf[i] = 0;
		i++;
		packet_buf[i] = EXP_PDU_TAG_SRC_PORT_LEN; /* tag length */;
		i++;
		packet_buf[i] = (exported_pdu_info->src_port & 0xff000000) >> 24;
		i++;
		packet_buf[i] = (exported_pdu_info->src_port & 0x00ff0000) >> 16;
		i++;
		packet_buf[i] = (exported_pdu_info->src_port & 0x0000ff00) >> 8;
		i++;
		packet_buf[i] = (exported_pdu_info->src_port & 0x000000ff);
		i++;
	}
Example #2
0
wtap_open_return_val k12_open(wtap *wth, int *err, gchar **err_info) {
    k12_src_desc_t* rec;
    guint8 header_buffer[K12_FILE_HDR_LEN];
    guint8* read_buffer;
    guint32 type;
    long offset;
    long len;
    guint port_type;
    guint32 rec_len;
    guint32 hwpart_len;
    guint32 name_len;
    guint32 stack_len;
    guint i;
    k12_t* file_data;

#ifdef DEBUG_K12
    gchar* env_level = getenv("K12_DEBUG_LEVEL");
    env_file = getenv("K12_DEBUG_FILENAME");
    if ( env_file ) {
        dbg_out = ws_fopen(env_file,"w");
        if (dbg_out == NULL) {
                dbg_out = stderr;
                K12_DBG(1,("unable to open K12 DEBUG FILENAME for writing!  Logging to standard error"));
        }
    }
    else
        dbg_out = stderr;
    if ( env_level ) debug_level = (unsigned int)strtoul(env_level,NULL,10);
    K12_DBG(1,("k12_open: ENTER debug_level=%u",debug_level));
#endif

    if ( !wtap_read_bytes(wth->fh,header_buffer,K12_FILE_HDR_LEN,err,err_info) ) {
        K12_DBG(1,("k12_open: FILE HEADER TOO SHORT OR READ ERROR"));
        if (*err != WTAP_ERR_SHORT_READ) {
            return WTAP_OPEN_ERROR;
        }
        return WTAP_OPEN_NOT_MINE;
    }

    if ( memcmp(header_buffer,k12_file_magic,8) != 0 ) {
        K12_DBG(1,("k12_open: BAD MAGIC"));
        return WTAP_OPEN_NOT_MINE;
    }

    offset = K12_FILE_HDR_LEN;

    file_data = new_k12_file_data();

    file_data->file_len = pntoh32( header_buffer + 0x8);
    if (memiszero(header_buffer + 0x10, K12_FILE_HDR_LEN - 0x10)) {
        /*
         * The rest of the file header is all zeroes.  That means
         * this is a file written by the old Wireshark code, and
         * a count of records in the file is at an offset of 0x0C.
         */
        file_data->num_of_records = pntoh32( header_buffer + 0x0C );
    } else {
        /*
         * There's at least one non-zero byte in the rest of the
         * header.  The value 8192 is at 0xC (page size?), and
         * what appears to be the number of records in the file
         * is at an offset of 0x24 and at an offset of 0x2c.
         *
         * If the two values are not the same, we fail; if that's
         * the case, we need to see the file to figure out which
         * of those two values, if any, is the count.
         */
        file_data->num_of_records = pntoh32( header_buffer + K12_FILE_HDR_RECORD_COUNT_1 );
        if ( file_data->num_of_records != pntoh32( header_buffer + K12_FILE_HDR_RECORD_COUNT_2 ) ) {
            *err = WTAP_ERR_BAD_FILE;
            *err_info = g_strdup_printf("k12: two different record counts, %u at 0x%02x and %u at 0x%02x",
                                        file_data->num_of_records,
                                        K12_FILE_HDR_RECORD_COUNT_1,
                                        pntoh32( header_buffer + K12_FILE_HDR_RECORD_COUNT_2 ),
                                        K12_FILE_HDR_RECORD_COUNT_2 );
            return WTAP_OPEN_ERROR;
        }
    }

    K12_DBG(5,("k12_open: FILE_HEADER OK: offset=%x file_len=%i records=%i",
            offset,
            file_data->file_len,
            file_data->num_of_records ));

    do {
        if ( file_data->num_of_records == 0 ) {
            *err = WTAP_ERR_SHORT_READ;
            destroy_k12_file_data(file_data);
            return WTAP_OPEN_ERROR;
        }

        len = get_record(file_data, wth->fh, offset, FALSE, err, err_info);

        if ( len < 0 ) {
            K12_DBG(1,("k12_open: BAD HEADER RECORD",len));
            destroy_k12_file_data(file_data);
            return WTAP_OPEN_ERROR;
        }
        if ( len == 0 ) {
            K12_DBG(1,("k12_open: BAD HEADER RECORD",len));
            *err = WTAP_ERR_SHORT_READ;
            destroy_k12_file_data(file_data);
            return WTAP_OPEN_ERROR;
        }

        read_buffer = file_data->seq_read_buff;

        rec_len = pntoh32( read_buffer + K12_RECORD_LEN );
        if (rec_len < K12_RECORD_TYPE + 4) {
            /* Record isn't long enough to have a type field */
            *err = WTAP_ERR_BAD_FILE;
            *err_info = g_strdup_printf("k12_open: record length %u < %u",
                                        rec_len, K12_RECORD_TYPE + 4);
            return WTAP_OPEN_ERROR;
        }
        type = pntoh32( read_buffer + K12_RECORD_TYPE );

        if ( (type & K12_MASK_PACKET) == K12_REC_PACKET ||
             (type & K12_MASK_PACKET) == K12_REC_D0020) {
            /*
             * we are at the first packet record, rewind and leave.
             */
            if (file_seek(wth->fh, offset, SEEK_SET, err) == -1) {
                destroy_k12_file_data(file_data);
                return WTAP_OPEN_ERROR;
            }
            K12_DBG(5,("k12_open: FIRST PACKET offset=%x",offset));
            break;
        }

        switch (type) {

        case K12_REC_SRCDSC:
        case K12_REC_SRCDSC2:
            rec = g_new0(k12_src_desc_t,1);

            if (rec_len < K12_SRCDESC_HWPART) {
                /*
                 * Record isn't long enough to have the fixed-length portion
                 * of the source descriptor field.
                 */
                *err = WTAP_ERR_BAD_FILE;
                *err_info = g_strdup_printf("k12_open: source descriptor record length %u < %u",
                                            rec_len, K12_SRCDESC_HWPART);
                destroy_k12_file_data(file_data);
                g_free(rec);
                return WTAP_OPEN_ERROR;
            }
            port_type = read_buffer[K12_SRCDESC_PORT_TYPE];
            hwpart_len = pntoh16( read_buffer + K12_SRCDESC_HWPARTLEN );
            name_len = pntoh16( read_buffer + K12_SRCDESC_NAMELEN );
            stack_len = pntoh16( read_buffer + K12_SRCDESC_STACKLEN );

            rec->input = pntoh32( read_buffer + K12_RECORD_SRC_ID );

            K12_DBG(5,("k12_open: INTERFACE RECORD offset=%x interface=%x",offset,rec->input));

            if (name_len == 0) {
                K12_DBG(5,("k12_open: failed (name_len == 0 in source description"));
                destroy_k12_file_data(file_data);
                g_free(rec);
                return WTAP_OPEN_NOT_MINE;
            }
            if (stack_len == 0) {
                K12_DBG(5,("k12_open: failed (stack_len == 0 in source description"));
                destroy_k12_file_data(file_data);
                g_free(rec);
                return WTAP_OPEN_NOT_MINE;
            }
            if (rec_len < K12_SRCDESC_HWPART + hwpart_len + name_len + stack_len) {
                /*
                 * Record isn't long enough to have the full source descriptor
                 * field, including the variable-length parts.
                 */
                *err = WTAP_ERR_BAD_FILE;
                *err_info = g_strdup_printf("k12_open: source descriptor record length %u < %u (%u + %u + %u + %u)",
                                            rec_len,
                                            K12_SRCDESC_HWPART + hwpart_len + name_len + stack_len,
                                            K12_SRCDESC_HWPART, hwpart_len, name_len, stack_len);
                destroy_k12_file_data(file_data);
                g_free(rec);
                return WTAP_OPEN_ERROR;
            }

            if (hwpart_len) {
                if (hwpart_len < 4) {
                    /* Hardware part isn't long enough to have a type field */
                    *err = WTAP_ERR_BAD_FILE;
                    *err_info = g_strdup_printf("k12_open: source descriptor hardware part length %u < 4",
                                                hwpart_len);
                    destroy_k12_file_data(file_data);
                    g_free(rec);
                    return WTAP_OPEN_ERROR;
                }
                switch(( rec->input_type = pntoh32( read_buffer + K12_SRCDESC_HWPART + K12_SRCDESC_HWPARTTYPE ) )) {
                    case K12_PORT_DS0S:
                        /* This appears to be variable-length */
                        rec->input_info.ds0mask = 0x00000000;
                        if (hwpart_len > K12_SRCDESC_DS0_MASK) {
                            for (i = 0; i < hwpart_len - K12_SRCDESC_DS0_MASK; i++) {
                                rec->input_info.ds0mask |= ( *(read_buffer + K12_SRCDESC_HWPART + K12_SRCDESC_DS0_MASK + i) == 0xff ) ? 1U<<(31-i) : 0x0;
                            }
                        }
                        break;
                    case K12_PORT_ATMPVC:
                        if (hwpart_len < K12_SRCDESC_ATM_VCI + 2) {
                            /* Hardware part isn't long enough to have ATM information */
                            *err = WTAP_ERR_BAD_FILE;
                            *err_info = g_strdup_printf("k12_open: source descriptor hardware part length %u < %u",
                                                        hwpart_len,
                                                        K12_SRCDESC_ATM_VCI + 2);
                            destroy_k12_file_data(file_data);
                            g_free(rec);
                            return WTAP_OPEN_ERROR;
                        }

                        rec->input_info.atm.vp = pntoh16( read_buffer + K12_SRCDESC_HWPART + K12_SRCDESC_ATM_VPI );
                        rec->input_info.atm.vc = pntoh16( read_buffer + K12_SRCDESC_HWPART + K12_SRCDESC_ATM_VCI );
                        break;
                    default:
                        break;
                }
            } else {
                /* Record viewer generated files don't have this information */
                if (port_type >= 0x14
                    && port_type <= 0x17) {
                    /* For ATM2_E1DS1, ATM2_E3DS3,
                       ATM2_STM1EL and ATM2_STM1OP */
                    rec->input_type = K12_PORT_ATMPVC;
                    rec->input_info.atm.vp = 0;
                    rec->input_info.atm.vc = 0;
                }
            }

            if (read_buffer[K12_SRCDESC_HWPART + hwpart_len + name_len - 1] != '\0') {
                *err = WTAP_ERR_BAD_FILE;
                *err_info = g_strdup("k12_open: source descriptor record contains non-null-terminated link-layer name");
                destroy_k12_file_data(file_data);
                g_free(rec);
                return WTAP_OPEN_ERROR;
            }
            if (read_buffer[K12_SRCDESC_HWPART + hwpart_len + name_len + stack_len - 1] != '\0') {
                *err = WTAP_ERR_BAD_FILE;
                *err_info = g_strdup("k12_open: source descriptor record contains non-null-terminated stack path");
                destroy_k12_file_data(file_data);
                g_free(rec);
                return WTAP_OPEN_ERROR;
            }
            rec->input_name = (gchar *)g_memdup(read_buffer + K12_SRCDESC_HWPART + hwpart_len, name_len);
            rec->stack_file = (gchar *)g_memdup(read_buffer + K12_SRCDESC_HWPART + hwpart_len + name_len, stack_len);

            ascii_strdown_inplace (rec->stack_file);

            g_hash_table_insert(file_data->src_by_id,GUINT_TO_POINTER(rec->input),rec);
            g_hash_table_insert(file_data->src_by_name,rec->stack_file,rec);
            break;

        case K12_REC_STK_FILE:
            K12_DBG(1,("k12_open: K12_REC_STK_FILE"));
            K12_DBG(1,("Field 1: 0x%08x",pntoh32( read_buffer + 0x08 )));
            K12_DBG(1,("Field 2: 0x%08x",pntoh32( read_buffer + 0x0c )));
            K12_ASCII_DUMP(1, read_buffer, rec_len, 16);
            break;

        default:
            K12_DBG(1,("k12_open: RECORD TYPE 0x%08x",type));
            break;
        }
        offset += len;
        file_data->num_of_records--;
    } while(1);

    wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_K12;
    wth->file_encap = WTAP_ENCAP_K12;
    wth->snapshot_length = 0;
    wth->subtype_read = k12_read;
    wth->subtype_seek_read = k12_seek_read;
    wth->subtype_close = k12_close;
    wth->priv = (void *)file_data;
    wth->file_tsprec = WTAP_TSPREC_NSEC;

    return WTAP_OPEN_MINE;
}
/* Parsing something like
 * <rawMsg
 *   protocol="Diameter"
 *   version="1">
 *    [truncated]010001244000012C01000...
 * </rawMsg>
 */
static wtap_open_return_val
write_packet_data(wtap_dumper *wdh, struct wtap_pkthdr *phdr, int *err, gchar **err_info, guint8 *file_buf)
{
	char *curr_pos, *next_pos;
	char proto_name_str[16];
	int tag_str_len = 0;
	int proto_str_len, raw_data_len, pkt_data_len,  exp_pdu_tags_len, i, j;
	guint8 *packet_buf;
	gchar chr;
	gint val1, val2;

	memset(proto_name_str, 0, sizeof(proto_name_str));
	/* Extract the protocol name */
	curr_pos = strstr(file_buf, "protocol=\"");
	if (!curr_pos){
		return WTAP_OPEN_ERROR;
	}
	curr_pos = curr_pos + 10;
	next_pos = strstr(curr_pos, "\"");
	proto_str_len = (int)(next_pos - curr_pos);
	if (proto_str_len > 15){
		return WTAP_OPEN_ERROR;
	}

	g_strlcpy(proto_name_str, curr_pos, proto_str_len+1);
	ascii_strdown_inplace(proto_name_str);

	/* Do string matching and replace with Wiresharks protocol name */
	if (strcmp(proto_name_str, "gtpv2-c") == 0){
		/* Change to gtpv2 */
		proto_name_str[5] = '\0';
		proto_name_str[6] = '\0';
		proto_str_len = 5;
	}
	/* XXX Do we need to check for function="S1" */
	if (strcmp(proto_name_str, "nas") == 0){
		/* Change to nas-eps_plain */
		g_strlcpy(proto_name_str, "nas-eps_plain", 14);
		proto_name_str[13] = '\0';
		proto_str_len = 13;
	}
	/* Find the start of the raw data*/
	curr_pos = strstr(next_pos, ">") + 1;
	next_pos = strstr(next_pos, "<");

	raw_data_len = (int)(next_pos - curr_pos);

	/* Calculate the space needed for exp pdu tags*/
	tag_str_len = (proto_str_len + 3) & 0xfffffffc;
	exp_pdu_tags_len = tag_str_len + 4;


	/* Allocate the packet buf */
	pkt_data_len = raw_data_len / 2;
	packet_buf = (guint8 *)g_malloc0(pkt_data_len + exp_pdu_tags_len +4);

	/* Fill packet buff */
	packet_buf[0] = 0;
	packet_buf[1] = 12; /* EXP_PDU_TAG_PROTO_NAME */
	packet_buf[2] = 0;
	packet_buf[3] = tag_str_len;
	for (i = 4, j = 0; j < tag_str_len; i++, j++){
		packet_buf[i] = proto_name_str[j];
	}

	/* Add end of options */
	packet_buf[i] = 0;
	i++;
	packet_buf[i] = 0;
	i++;
	packet_buf[i] = 0;
	i++;
	packet_buf[i] = 0;
	i++;
	exp_pdu_tags_len = exp_pdu_tags_len + 4;

	/* Convert the hex raw msg data to binary and write to the packet buf*/
	for (; i < (pkt_data_len + exp_pdu_tags_len); i++){
		chr = *curr_pos;
		val1 = g_ascii_xdigit_value(chr);
		curr_pos++;
		chr = *curr_pos;
		val2 = g_ascii_xdigit_value(chr);
		if ((val1 != -1) && (val2 != -1)){
			packet_buf[i] = ((guint8)val1 * 16) + val2;
		}
		else{
			/* Something wrong, bail out */
			g_free(packet_buf);
			return WTAP_OPEN_ERROR;
		}
		curr_pos++;
	}
	/* Construct the phdr */
	memset(phdr, 0, sizeof(struct wtap_pkthdr));
	phdr->rec_type = REC_TYPE_PACKET;
	phdr->presence_flags = 0; /* yes, we have no bananas^Wtime stamp */

	phdr->caplen = pkt_data_len + exp_pdu_tags_len;
	phdr->len = pkt_data_len + exp_pdu_tags_len;

	phdr->ts.secs = 0;
	phdr->ts.nsecs = 0;

	if (!wtap_dump(wdh, phdr, packet_buf, err, err_info)) {
		switch (*err) {

		case WTAP_ERR_UNWRITABLE_REC_DATA:
			g_free(err_info);
			break;

		default:
			break;
		}
		g_free(packet_buf);
		return WTAP_OPEN_ERROR;
	}

	g_free(packet_buf);
	return WTAP_OPEN_MINE;
}
/* Parsing something like
 * <rawMsg
 *   protocol="Diameter"
 *   version="1">
 *    [truncated]010001244000012C01000...
 * </rawMsg>
 */
static wtap_open_return_val
write_packet_data(wtap_dumper *wdh, struct wtap_pkthdr *phdr, int *err, gchar **err_info, guint8 *file_buf, time_t start_time, int ms, exported_pdu_info_t *exported_pdu_info)
{
	char *curr_pos, *next_pos;
	char proto_name_str[16];
	int tag_str_len = 0;
	int proto_str_len, raw_data_len, pkt_data_len,  exp_pdu_tags_len, i, j;
	guint8 *packet_buf;
	gchar chr;
	gint val1, val2;
	gboolean port_type_defined = FALSE;

	memset(proto_name_str, 0, sizeof(proto_name_str));
	/* Extract the protocol name */
	curr_pos = strstr(file_buf, "protocol=\"");
	if (!curr_pos){
		return WTAP_OPEN_ERROR;
	}
	curr_pos = curr_pos + 10;
	next_pos = strstr(curr_pos, "\"");
	proto_str_len = (int)(next_pos - curr_pos);
	if (proto_str_len > 15){
		return WTAP_OPEN_ERROR;
	}

	g_strlcpy(proto_name_str, curr_pos, proto_str_len+1);
	ascii_strdown_inplace(proto_name_str);

	/* Do string matching and replace with Wiresharks protocol name */
	if (strcmp(proto_name_str, "gtpv2-c") == 0){
		/* Change to gtpv2 */
		proto_name_str[5] = '\0';
		proto_name_str[6] = '\0';
		proto_str_len = 5;
	}
	/* XXX Do we need to check for function="S1" */
	if (strcmp(proto_name_str, "nas") == 0){
		/* Change to nas-eps_plain */
		g_strlcpy(proto_name_str, "nas-eps_plain", 14);
		proto_name_str[13] = '\0';
		proto_str_len = 13;
	}
	/* Find the start of the raw data*/
	curr_pos = strstr(next_pos, ">") + 1;
	next_pos = strstr(next_pos, "<");

	raw_data_len = (int)(next_pos - curr_pos);

	/* Calculate the space needed for exp pdu tags*/
	tag_str_len = (proto_str_len + 3) & 0xfffffffc;
	exp_pdu_tags_len = tag_str_len + 4;

	if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_IP_SRC_BIT) == EXP_PDU_TAG_IP_SRC_BIT) {
		exp_pdu_tags_len += 4 + EXP_PDU_TAG_IPV4_SRC_LEN;
	}
	if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_SRC_PORT_BIT) == EXP_PDU_TAG_SRC_PORT_BIT) {
		if (!port_type_defined) {
			exp_pdu_tags_len += 4 + EXP_PDU_TAG_PORT_TYPE_LEN;
			port_type_defined = TRUE;
		}
		exp_pdu_tags_len += 4 + EXP_PDU_TAG_SRC_PORT_LEN;
	}

	if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_IP_DST_BIT) == EXP_PDU_TAG_IP_DST_BIT) {
		exp_pdu_tags_len += 4 + EXP_PDU_TAG_IPV4_DST_LEN;
	}

	if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_DST_PORT_BIT) == EXP_PDU_TAG_DST_PORT_BIT) {
		if (!port_type_defined) {
			exp_pdu_tags_len += 4 + EXP_PDU_TAG_PORT_TYPE_LEN;
			port_type_defined = TRUE;
		}
		exp_pdu_tags_len += 4 + EXP_PDU_TAG_SRC_PORT_LEN;
	}

	port_type_defined = FALSE;

	/* Allocate the packet buf */
	pkt_data_len = raw_data_len / 2;
	packet_buf = (guint8 *)g_malloc0(pkt_data_len + exp_pdu_tags_len +4);

	/* Fill packet buff */
	packet_buf[0] = 0;
	packet_buf[1] = 12; /* EXP_PDU_TAG_PROTO_NAME */
	packet_buf[2] = 0;
	packet_buf[3] = tag_str_len;
	for (i = 4, j = 0; j < tag_str_len; i++, j++){
		packet_buf[i] = proto_name_str[j];
	}

	if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_IP_SRC_BIT) == EXP_PDU_TAG_IP_SRC_BIT) {
		packet_buf[i] = 0;
		i++;
		packet_buf[i] = EXP_PDU_TAG_IPV4_SRC;
		i++;
		packet_buf[i] = 0;
		i++;
		packet_buf[i] = EXP_PDU_TAG_IPV4_SRC_LEN; /* tag length */;
		i++;
		packet_buf[i] = exported_pdu_info->src_ipv4_d1;
		i++;
		packet_buf[i] = exported_pdu_info->src_ipv4_d2;
		i++;
		packet_buf[i] = exported_pdu_info->src_ipv4_d3;
		i++;
		packet_buf[i] = exported_pdu_info->src_ipv4_d4;
		i++;
	}

	if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_SRC_PORT_BIT) == EXP_PDU_TAG_SRC_PORT_BIT) {
		if (!port_type_defined) {
			port_type_defined = TRUE;
			packet_buf[i] = 0;
			i++;
			packet_buf[i] = EXP_PDU_TAG_PORT_TYPE;
			i++;
			packet_buf[i] = 0;
			i++;
			packet_buf[i] = EXP_PDU_TAG_PORT_TYPE_LEN; /* tag length */;
			i++;
			packet_buf[i] = (exported_pdu_info->ptype & 0xff000000) >> 24;
			i++;
			packet_buf[i] = (exported_pdu_info->ptype & 0x00ff0000) >> 16;
			i++;
			packet_buf[i] = (exported_pdu_info->ptype & 0x0000ff00) >> 8;
			i++;
			packet_buf[i] = (exported_pdu_info->ptype & 0x000000ff);
			i++;
		}
		packet_buf[i] = 0;
		i++;
		packet_buf[i] = EXP_PDU_TAG_SRC_PORT;
		i++;
		packet_buf[i] = 0;
		i++;
		packet_buf[i] = EXP_PDU_TAG_SRC_PORT_LEN; /* tag length */;
		i++;
		packet_buf[i] = (exported_pdu_info->src_port & 0xff000000) >> 24;
		i++;
		packet_buf[i] = (exported_pdu_info->src_port & 0x00ff0000) >> 16;
		i++;
		packet_buf[i] = (exported_pdu_info->src_port & 0x0000ff00) >> 8;
		i++;
		packet_buf[i] = (exported_pdu_info->src_port & 0x000000ff);
		i++;
	}
Example #5
0
static int
dissect_rtspmessage(tvbuff_t *tvb, int offset, packet_info *pinfo,
	proto_tree *tree)
{
	proto_tree		*rtsp_tree = NULL;
	proto_tree		*sub_tree = NULL;
	proto_item		*ti = NULL;
	const guchar		*line;
	gint			next_offset;
	const guchar		*linep, *lineend;
	int			orig_offset;
	int			first_linelen, linelen;
	int			line_end_offset;
	int			colon_offset;
	gboolean		is_request_or_reply;
	gboolean		body_requires_content_len;
	gboolean		saw_req_resp_or_header;
	guchar			c;
	rtsp_type_t		rtsp_type;
	gboolean		is_header;
	int			datalen;
	int			content_length;
	int			reported_datalen;
	int			value_offset;
	int			value_len;
	e164_info_t		e164_info;
	gint			rdt_feature_level = 0;
	gchar			*media_type_str_lower_case = NULL;
	int			semi_colon_offset;
	int			par_end_offset;

	/*
	 * Is this a request or response?
	 *
	 * 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.
	 */
	first_linelen = tvb_find_line_end(tvb, offset,
	    tvb_ensure_length_remaining(tvb, offset), &next_offset,
	    FALSE);

	/*
	 * Is the first line a request or response?
	 */
	line = tvb_get_ptr(tvb, offset, first_linelen);
	is_request_or_reply = is_rtsp_request_or_reply(line, first_linelen,
	    &rtsp_type);
	if (is_request_or_reply) {
                /*
		 * Yes, it's a request or response.
		 * Do header desegmentation if we've been told to,
		 * and do body desegmentation if we've been told to and
		 * we find a Content-Length header.
		 */
		if (!req_resp_hdrs_do_reassembly(tvb, offset, pinfo,
		    rtsp_desegment_headers, rtsp_desegment_body)) {
			/*
			 * More data needed for desegmentation.
			 */
			return -1;
		}
	}

	/*
	 * RFC 2326 says that a content length must be specified
	 * in requests that have a body, although section 4.4 speaks
	 * of a server closing the connection indicating the end of
	 * a reply body.
	 *
	 * We assume that an absent content length in a request means
	 * that we don't have a body, and that an absent content length
	 * in a reply means that the reply body runs to the end of
	 * the connection.  If the first line is neither, we assume
	 * that whatever follows a blank line should be treated as a
	 * body; there's not much else we can do, as we're jumping
	 * into the message in the middle.
	 *
	 * XXX - if there was no Content-Length entity header, we should
	 * accumulate all data until the end of the connection.
	 * That'd require that the TCP dissector call subdissectors
	 * for all frames with FIN, even if they contain no data,
	 * which would require subdissectors to deal intelligently
	 * with empty segments.
	 */
	if (rtsp_type == RTSP_REQUEST)
		body_requires_content_len = TRUE;
	else
		body_requires_content_len = FALSE;

	col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTSP");
	if (check_col(pinfo->cinfo, COL_INFO)) {
		/*
		 * Put the first line from the buffer into the summary
 		 * if it's an RTSP request or reply (but leave out the
		 * line terminator).
		 * Otherwise, just call it a continuation.
		 *
		 * 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.
		 */
		line = tvb_get_ptr(tvb, offset, first_linelen);
		if (is_request_or_reply)
			if ( rtsp_type == RTSP_REPLY ) {
				col_set_str(pinfo->cinfo, COL_INFO, "Reply: ");
				col_append_str(pinfo->cinfo, COL_INFO,
					format_text(line, first_linelen));
			}
			else
				col_add_str(pinfo->cinfo, COL_INFO,
					format_text(line, first_linelen));

		else
			col_set_str(pinfo->cinfo, COL_INFO, "Continuation");

	}

	orig_offset = offset;
	if (tree) {
		ti = proto_tree_add_item(tree, proto_rtsp, tvb, offset,	-1,
		    FALSE);
		rtsp_tree = proto_item_add_subtree(ti, ett_rtsp);
	}

	/*
	 * We haven't yet seen a Content-Length header.
	 */
	content_length = -1;

	/*
	 * Process the packet data, a line at a time.
	 */
	saw_req_resp_or_header = FALSE;	/* haven't seen anything yet */
	while (tvb_reported_length_remaining(tvb, offset) != 0) {
		/*
		 * We haven't yet concluded that this is a header.
		 */
		is_header = FALSE;

		/*
		 * Find the end of the line.
		 */
		linelen = tvb_find_line_end(tvb, offset,
		    tvb_ensure_length_remaining(tvb, offset), &next_offset,
		    FALSE);
		if (linelen < 0)
			return -1;
		line_end_offset = offset + linelen;
		/*
		 * colon_offset may be -1
		 */
		colon_offset = tvb_find_guint8(tvb, offset, linelen, ':');


		/*
		 * Get a buffer that refers to the line.
		 */
		line = tvb_get_ptr(tvb, offset, linelen);
		lineend = line + linelen;

		/*
		 * OK, does it look like an RTSP request or response?
		 */
		is_request_or_reply = is_rtsp_request_or_reply(line, linelen, &rtsp_type);
		if (is_request_or_reply)
			goto is_rtsp;

		/*
		 * No.  Does it look like a blank line (as would appear
		 * at the end of an RTSP request)?
		 */
		if (linelen == 0)
			goto is_rtsp;	/* Yes. */

		/*
		 * No.  Does it look like a header?
		 */
		linep = line;
		while (linep < lineend) {
			c = *linep++;

			/*
			 * This must be a CHAR to be part of a token; that
			 * means it must be ASCII.
			 */
			if (!isascii(c))
				break;	/* not ASCII, thus not a CHAR */

			/*
			 * This mustn't be a CTL to be part of a token.
			 *
			 * XXX - what about leading LWS on continuation
			 * lines of a header?
			 */
			if (iscntrl(c))
				break;	/* CTL, not part of a header */

			switch (c) {

			case '(':
			case ')':
			case '<':
			case '>':
			case '@':
			case ',':
			case ';':
			case '\\':
			case '"':
			case '/':
			case '[':
			case ']':
			case '?':
			case '=':
			case '{':
			case '}':
				/*
				 * It's a tspecial, so it's not
				 * part of a token, so it's not
				 * a field name for the beginning
				 * of a header.
				 */
				goto not_rtsp;

			case ':':
				/*
				 * This ends the token; we consider
				 * this to be a header.
				 */
				is_header = TRUE;
				goto is_rtsp;

			case ' ':
			case '\t':
				/*
				 * LWS (RFC-2616, 4.2); continue the previous
				 * header.
				 */
				goto is_rtsp;
			}
		}

		/*
		 * We haven't seen the colon, but everything else looks
		 * OK for a header line.
		 *
		 * If we've already seen an RTSP request or response
		 * line, or a header line, and we're at the end of
		 * the tvbuff, we assume this is an incomplete header
		 * line.  (We quit this loop after seeing a blank line,
		 * so if we've seen a request or response line, or a
		 * header line, this is probably more of the request
		 * or response we're presumably seeing.  There is some
		 * risk of false positives, but the same applies for
		 * full request or response lines or header lines,
		 * although that's less likely.)
		 *
		 * We throw an exception in that case, by checking for
		 * the existence of the next byte after the last one
		 * in the line.  If it exists, "tvb_ensure_bytes_exist()"
		 * throws no exception, and we fall through to the
		 * "not RTSP" case.  If it doesn't exist,
		 * "tvb_ensure_bytes_exist()" will throw the appropriate
		 * exception.
		 */
		if (saw_req_resp_or_header)
			tvb_ensure_bytes_exist(tvb, offset, linelen + 1);

	not_rtsp:
		/*
		 * We don't consider this part of an RTSP request or
		 * reply, so we don't display it.
		 */
		break;

	is_rtsp:
		/*
		 * Process this line.
		 */
		if (linelen == 0) {
			/*
			 * This is a blank line, which means that
			 * whatever follows it isn't part of this
			 * request or reply.
			 */
			proto_tree_add_text(rtsp_tree, tvb, offset,
			                    next_offset - offset, "%s",
			                    tvb_format_text(tvb, offset, next_offset - offset));
			offset = next_offset;
			break;
		}

		/*
		 * Not a blank line - either a request, a reply, or a header
		 * line.
		 */
		saw_req_resp_or_header = TRUE;
		if (rtsp_tree) {

			switch (rtsp_type)
			{
				case RTSP_REQUEST:
					process_rtsp_request(tvb, offset, line, linelen, next_offset, rtsp_tree);
					break;
	
				case RTSP_REPLY:
					process_rtsp_reply(tvb, offset, line, linelen, next_offset, rtsp_tree);
					break;
	
				case RTSP_NOT_FIRST_LINE:
					/* Drop through, it may well be a header line */
					break;
			}
		}

		if (is_header)
		{
			/* We know that colon_offset must be set */
			
			/* Skip whitespace after the colon. */
			value_offset = colon_offset + 1;
			while ((value_offset < line_end_offset) &&
				   ((c = tvb_get_guint8(tvb, value_offset)) == ' ' || c == '\t'))
			{
				value_offset++;
			}
			value_len = line_end_offset - value_offset;

			/*
			 * Process some headers specially.
			 */
#define HDR_MATCHES(header) \
	( (size_t)linelen > STRLEN_CONST(header) && \
	 g_ascii_strncasecmp(line, (header), STRLEN_CONST(header)) == 0)

			if (HDR_MATCHES(rtsp_transport))
			{
				proto_tree_add_string(rtsp_tree, hf_rtsp_transport, tvb,
				                      offset, linelen,
				                      tvb_format_text(tvb, value_offset,
				                                      value_len));

				/*
				 * Based on the port numbers specified
				 * in the Transport: header, set up
				 * a conversation that will be dissected
				 * with the appropriate dissector.
				 */
				rtsp_create_conversation(pinfo, line, linelen, rdt_feature_level);
			} else if (HDR_MATCHES(rtsp_content_type))
			{
				proto_tree_add_string(rtsp_tree, hf_rtsp_content_type,
				                      tvb, offset, linelen,
				                      tvb_format_text(tvb, value_offset,
				                                      value_len));

				offset = offset + STRLEN_CONST(rtsp_content_type);
				/* Skip wsp */
				offset = tvb_skip_wsp(tvb, offset, value_len);
				semi_colon_offset = tvb_find_guint8(tvb, value_offset, value_len, ';');
				if ( semi_colon_offset != -1) {
					/* m-parameter present */
					par_end_offset = tvb_skip_wsp_return(tvb, semi_colon_offset-1);
					value_len = par_end_offset - offset;
				}

				media_type_str_lower_case = ascii_strdown_inplace(
                                    (gchar *)tvb_get_ephemeral_string(tvb, offset, value_len));

			} else if (HDR_MATCHES(rtsp_content_length))
			{
				proto_tree_add_uint(rtsp_tree, hf_rtsp_content_length,
				                    tvb, offset, linelen,
				                    atoi(tvb_format_text(tvb, value_offset,
				                                         value_len)));

				/*
				 * Only the amount specified by the
				 * Content-Length: header should be treated
				 * as payload.
				 */
				content_length = rtsp_get_content_length(line, linelen);

			} else if (HDR_MATCHES(rtsp_Session))
			{
				/* Put the value into the protocol tree */
				proto_tree_add_string(rtsp_tree, hf_rtsp_session, tvb,
				                      offset, linelen,
				                      tvb_format_text(tvb, value_offset, value_len));

			} else if (HDR_MATCHES(rtsp_X_Vig_Msisdn)) {
				/*
				 * Extract the X_Vig_Msisdn string
				 */
				if (colon_offset != -1)
				{
					/* Put the value into the protocol tree */
					ti = proto_tree_add_string(rtsp_tree, hf_rtsp_X_Vig_Msisdn,tvb,
					                           offset, linelen ,
					                           tvb_format_text(tvb, value_offset, value_len));
					sub_tree = proto_item_add_subtree(ti, ett_rtsp_method);

					e164_info.e164_number_type = CALLING_PARTY_NUMBER;
					e164_info.nature_of_address = 0;

					e164_info.E164_number_str = tvb_get_ephemeral_string(tvb, value_offset,
					                                              value_len);
					e164_info.E164_number_length = value_len;
					dissect_e164_number(tvb, sub_tree, value_offset,
					                    value_len, e164_info);
				}
			} else if (HDR_MATCHES(rtsp_rdt_feature_level))
			{
				rdt_feature_level = atoi(tvb_format_text(tvb, value_offset,
				                                         value_len));
				proto_tree_add_uint(rtsp_tree, hf_rtsp_rdtfeaturelevel,
				                    tvb, offset, linelen,
				                    atoi(tvb_format_text(tvb, value_offset,
				                                         value_len)));
			}
			else
			{
				/* Default case for headers. Show line as text */
				proto_tree_add_text(rtsp_tree, tvb, offset,
				                    next_offset - offset, "%s",
				                    tvb_format_text(tvb, offset, next_offset - offset));
			}
		}
		else if (rtsp_type == RTSP_NOT_FIRST_LINE)
		{
			/* Catch-all for all other lines... Show line as text.
			   TODO: should these be shown as errors? */
			proto_tree_add_text(rtsp_tree, tvb, offset,
			                    next_offset - offset, "%s",
			                    tvb_format_text(tvb, offset, next_offset - offset));
		}
		
		offset = next_offset;
	}

	/*
	 * Have now read all of the lines of this message.
	 *
	 * If a content length was supplied, the amount of data to be
	 * processed as RTSP payload is the minimum of the content
	 * length and the amount of data remaining in the frame.
	 *
	 * If no content length was supplied (or if a bad content length
	 * was supplied), the amount of data to be processed is the amount
	 * of data remaining in the frame.
	 */
	datalen = tvb_length_remaining(tvb, offset);
	reported_datalen = tvb_reported_length_remaining(tvb, offset);
	if (content_length != -1) {
		/*
		 * Content length specified; display only that amount
		 * as payload.
		 */
		if (datalen > content_length)
			datalen = content_length;

		/*
		 * XXX - limit the reported length in the tvbuff we'll
		 * hand to a subdissector to be no greater than the
		 * content length.
		 *
		 * We really need both unreassembled and "how long it'd
		 * be if it were reassembled" lengths for tvbuffs, so
		 * that we throw the appropriate exceptions for
		 * "not enough data captured" (running past the length),
		 * "packet needed reassembly" (within the length but
		 * running past the unreassembled length), and
		 * "packet is malformed" (running past the reassembled
		 * length).
		 */
		if (reported_datalen > content_length)
			reported_datalen = content_length;
	} else {
		/*
		 * No content length specified; if this message doesn't
		 * have a body if no content length is specified, process
		 * nothing as payload.
		 */
		if (body_requires_content_len)
			datalen = 0;
	}

	if (datalen > 0) {
		/*
		 * There's stuff left over; process it.
		 */
		tvbuff_t *new_tvb;

		/*
		 * Now create a tvbuff for the Content-type stuff and
		 * dissect it.
		 *
		 * The amount of data to be processed that's
		 * available in the tvbuff is "datalen", which
		 * is the minimum of the amount of data left in
		 * the tvbuff and any specified content length.
		 *
		 * The amount of data to be processed that's in
		 * this frame, regardless of whether it was
		 * captured or not, is "reported_datalen",
		 * which, if no content length was specified,
		 * is -1, i.e. "to the end of the frame.
		 */
		new_tvb = tvb_new_subset(tvb, offset, datalen,
			    reported_datalen);

		if (media_type_str_lower_case && 
			dissector_try_string(media_type_dissector_table,
				media_type_str_lower_case,
				new_tvb, pinfo, rtsp_tree)){
			
		}else {
			/*
			 * Fix up the top-level item so that it doesn't
			 * include the SDP stuff.
			 */
			if (ti != NULL)
				proto_item_set_len(ti, offset);

			if (tvb_get_guint8(tvb, offset) == RTSP_FRAMEHDR) {
				/*
				 * This is interleaved stuff; don't
				 * treat it as raw data - set "datalen"
				 * to 0, so we won't skip the offset
				 * past it, which will cause our
				 * caller to process that stuff itself.
				 */
				datalen = 0;
			} else {
				proto_tree_add_text(rtsp_tree, tvb, offset,
				    datalen, "Data (%d bytes)",
				    reported_datalen);
			}
		}

		/*
		 * We've processed "datalen" bytes worth of data
		 * (which may be no data at all); advance the
		 * offset past whatever data we've processed.
		 */
		offset += datalen;
	}
	return offset - orig_offset;
}
Example #6
0
int k12_open(wtap *wth, int *err, gchar **err_info) {
    k12_src_desc_t* rec;
    guint8 header_buffer[0x200];
    guint8* read_buffer;
    guint32 type;
    long offset;
    long len;
    guint32 rec_len;
    guint32 extra_len;
    guint32 name_len;
    guint32 stack_len;
    guint i;
    k12_t* file_data;

#ifdef DEBUG_K12
    gchar* env_level = getenv("K12_DEBUG_LEVEL");
    env_file = getenv("K12_DEBUG_FILENAME");
    if ( env_file ) {
        dbg_out = ws_fopen(env_file,"w");
        if (dbg_out == NULL) {
            dbg_out = stderr;
            K12_DBG(1,("unable to open K12 DEBUG FILENAME for writing!  Logging to standard error"));
        }
    }
    else
        dbg_out = stderr;
    if ( env_level ) debug_level = (unsigned int)strtoul(env_level,NULL,10);
    K12_DBG(1,("k12_open: ENTER debug_level=%u",debug_level));
#endif

    if ( file_read(header_buffer,0x200,wth->fh) != 0x200 ) {
        K12_DBG(1,("k12_open: FILE HEADER TOO SHORT OR READ ERROR"));
        *err = file_error(wth->fh, err_info);
        if (*err != 0 && *err != WTAP_ERR_SHORT_READ) {
            return -1;
        }
        return 0;
    } else {
        if ( memcmp(header_buffer,k12_file_magic,8) != 0 ) {
            K12_DBG(1,("k12_open: BAD MAGIC"));
            return 0;
        }
    }

    offset = 0x200;

    file_data = new_k12_file_data();

    file_data->file_len = pntoh32( header_buffer + 0x8);
    file_data->num_of_records = pntoh32( header_buffer + 0xC );

    K12_DBG(5,("k12_open: FILE_HEADER OK: offset=%x file_len=%i records=%i",
               offset,
               file_data->file_len,
               file_data->num_of_records ));

    do {

        len = get_record(file_data, wth->fh, offset, FALSE, err, err_info);

        if ( len < 0 ) {
            K12_DBG(1,("k12_open: BAD HEADER RECORD",len));
            destroy_k12_file_data(file_data);
            return -1;
        }
        if (len == 0) {
            K12_DBG(1,("k12_open: BAD HEADER RECORD",len));
            *err = WTAP_ERR_SHORT_READ;
            destroy_k12_file_data(file_data);
            return -1;
        }

        if (len == 0) {
            K12_DBG(1,("k12_open: BAD HEADER RECORD",len));
            *err = WTAP_ERR_SHORT_READ;
            destroy_k12_file_data(file_data);
            return -1;
        }

        read_buffer = file_data->seq_read_buff;

        rec_len = pntoh32( read_buffer + K12_RECORD_LEN );
        if (rec_len < K12_RECORD_TYPE + 4) {
            /* Record isn't long enough to have a type field */
            *err = WTAP_ERR_BAD_FILE;
            *err_info = g_strdup_printf("k12_open: record length %u < %u",
                                        rec_len, K12_RECORD_TYPE + 4);
            return -1;
        }
        type = pntoh32( read_buffer + K12_RECORD_TYPE );

        if ( (type & K12_MASK_PACKET) == K12_REC_PACKET ||
                (type & K12_MASK_PACKET) == K12_REC_D0020) {
            /*
             * we are at the first packet record, rewind and leave.
             */
            if (file_seek(wth->fh, offset, SEEK_SET, err) == -1) {
                destroy_k12_file_data(file_data);
                return -1;
            }
            K12_DBG(5,("k12_open: FIRST PACKET offset=%x",offset));
            break;
        } else if (type == K12_REC_SRCDSC || type == K12_REC_SRCDSC2 ) {
            rec = g_new0(k12_src_desc_t,1);

            if (rec_len < K12_SRCDESC_STACKLEN + 2) {
                /* Record isn't long enough to have a stack length field */
                *err = WTAP_ERR_BAD_FILE;
                *err_info = g_strdup_printf("k12_open: source descriptor record length %u < %u",
                                            rec_len, K12_SRCDESC_STACKLEN + 2);
                return -1;
            }
            extra_len = pntoh16( read_buffer + K12_SRCDESC_EXTRALEN );
            name_len = pntoh16( read_buffer + K12_SRCDESC_NAMELEN );
            stack_len = pntoh16( read_buffer + K12_SRCDESC_STACKLEN );

            rec->input = pntoh32( read_buffer + K12_RECORD_SRC_ID );

            K12_DBG(5,("k12_open: INTERFACE RECORD offset=%x interface=%x",offset,rec->input));

            if (name_len == 0 || stack_len == 0
                    || 0x20 + extra_len + name_len + stack_len > rec_len ) {
                g_free(rec);
                K12_DBG(5,("k12_open: failed (name_len == 0 || stack_len == 0 "
                           "|| 0x20 + extra_len + name_len + stack_len > rec_len)  extra_len=%i name_len=%i stack_len=%i"));
                destroy_k12_file_data(file_data);
                return 0;
            }

            if (extra_len) {
                if (rec_len < K12_SRCDESC_EXTRATYPE + 4) {
                    /* Record isn't long enough to have a source descriptor extra type field */
                    *err = WTAP_ERR_BAD_FILE;
                    *err_info = g_strdup_printf("k12_open: source descriptor record length %u < %u",
                                                rec_len, K12_SRCDESC_EXTRATYPE + 4);
                    return -1;
                }
                switch(( rec->input_type = pntoh32( read_buffer + K12_SRCDESC_EXTRATYPE ) )) {
                case K12_PORT_DS0S:
                    if (rec_len < K12_SRCDESC_DS0_MASK + 32) {
                        /* Record isn't long enough to have a source descriptor extra type field */
                        *err = WTAP_ERR_BAD_FILE;
                        *err_info = g_strdup_printf("k12_open: source descriptor record length %u < %u",
                                                    rec_len, K12_SRCDESC_DS0_MASK + 12);
                        return -1;
                    }

                    rec->input_info.ds0mask = 0x00000000;

                    for (i = 0; i < 32; i++) {
                        rec->input_info.ds0mask |= ( *(read_buffer + K12_SRCDESC_DS0_MASK + i) == 0xff ) ? 0x1<<(31-i) : 0x0;
                    }

                    break;
                case K12_PORT_ATMPVC:
                    if (rec_len < K12_SRCDESC_ATM_VCI + 2) {
                        /* Record isn't long enough to have a source descriptor extra type field */
                        *err = WTAP_ERR_BAD_FILE;
                        *err_info = g_strdup_printf("k12_open: source descriptor record length %u < %u",
                                                    rec_len, K12_SRCDESC_DS0_MASK + 12);
                        return -1;
                    }

                    rec->input_info.atm.vp = pntoh16( read_buffer + K12_SRCDESC_ATM_VPI );
                    rec->input_info.atm.vc = pntoh16( read_buffer + K12_SRCDESC_ATM_VCI );
                    break;
                default:
                    break;
                }
            } else {
                /* Record viewer generated files don't have this information */
                if (rec_len < K12_SRCDESC_PORT_TYPE + 1) {
                    /* Record isn't long enough to have a source descriptor extra type field */
                    *err = WTAP_ERR_BAD_FILE;
                    *err_info = g_strdup_printf("k12_open: source descriptor record length %u < %u",
                                                rec_len, K12_SRCDESC_DS0_MASK + 12);
                    return -1;
                }
                if (read_buffer[K12_SRCDESC_PORT_TYPE] >= 0x14
                        && read_buffer[K12_SRCDESC_PORT_TYPE] <= 0x17) {
                    /* For ATM2_E1DS1, ATM2_E3DS3,
                       ATM2_STM1EL and ATM2_STM1OP */
                    rec->input_type = K12_PORT_ATMPVC;
                    rec->input_info.atm.vp = 0;
                    rec->input_info.atm.vc = 0;
                }
            }

            /* XXX - this is assumed, in a number of places (not just in the
               ascii_strdown_inplace() call below) to be null-terminated;
               is that guaranteed (even with a corrupt file)?
            Obviously not, as a corrupt file could contain anything
            here; the Tektronix document says the strings "must end
            with \0", but a bad file could fail to add the \0. */
            if (rec_len < K12_SRCDESC_EXTRATYPE + extra_len + name_len + stack_len) {
                /* Record isn't long enough to have a source descriptor extra type field */
                *err = WTAP_ERR_BAD_FILE;
                *err_info = g_strdup_printf("k12_open: source descriptor record length %u < %u",
                                            rec_len, K12_SRCDESC_EXTRATYPE + extra_len + name_len + stack_len);
                return -1;
            }
            rec->input_name = (gchar *)g_memdup(read_buffer + K12_SRCDESC_EXTRATYPE + extra_len, name_len);
            rec->stack_file = (gchar *)g_memdup(read_buffer + K12_SRCDESC_EXTRATYPE + extra_len + name_len, stack_len);

            ascii_strdown_inplace (rec->stack_file);

            g_hash_table_insert(file_data->src_by_id,GUINT_TO_POINTER(rec->input),rec);
            g_hash_table_insert(file_data->src_by_name,rec->stack_file,rec);

            offset += len;
            continue;
        } else if (type == K12_REC_STK_FILE) {
            K12_DBG(1,("k12_open: K12_REC_STK_FILE"));
            K12_DBG(1,("Field 1: 0x%08x",pntoh32( read_buffer + 0x08 )));
            K12_DBG(1,("Field 2: 0x%08x",pntoh32( read_buffer + 0x0c )));
            K12_ASCII_DUMP(1, read_buffer, rec_len, 0x10);

            offset += len;
            continue;
        } else {
            K12_DBG(1,("k12_open: RECORD TYPE 0x%08x",type));
            offset += len;
            continue;
        }
    } while(1);

    wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_K12;
    wth->file_encap = WTAP_ENCAP_K12;
    wth->snapshot_length = 0;
    wth->subtype_read = k12_read;
    wth->subtype_seek_read = k12_seek_read;
    wth->subtype_close = k12_close;
    wth->priv = (void *)file_data;
    wth->tsprecision = WTAP_FILE_TSPREC_NSEC;

    return 1;
}
Example #7
0
/* Code to actually dissect the packets */
static int
dissect_msrp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
	gint offset = 0;
	gint next_offset = 0;
	proto_item *ti, *th, *msrp_headers_item, *msrp_element_item;
	proto_tree *msrp_tree, *reqresp_tree, *raw_tree, *msrp_hdr_tree, *msrp_end_tree;
	proto_tree *msrp_element_tree, *msrp_data_tree;
	gint linelen;
	gint space_offset;
	gint token_2_start;
	guint token_2_len;
	gint token_3_start;
	guint token_3_len;
	gint token_4_start = 0;
	guint token_4_len = 0;
	gboolean is_msrp_response;
	gint end_line_offset;
	gint end_line_len;
	gint line_end_offset;
	gint message_end_offset;
	gint colon_offset;
	char *transaction_id_str = NULL;
	gint header_len;
	gint hf_index;
	gint value_offset;
	guchar c;
	gint value_len;
	char *value;
	gboolean have_body = FALSE;
	gboolean found_match = FALSE;
	gint content_type_len, content_type_parameter_str_len;
	gchar *media_type_str_lower_case = NULL;
	char *content_type_parameter_str = NULL;
	tvbuff_t *next_tvb;
	gint parameter_offset;
	gint semi_colon_offset;

	if ( !check_msrp_header(tvb)){
		return 0;
	}
	/* We have a MSRP header with at least three tokens
	 *
	 * 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()" calls below won't throw exceptions.	 *
	 */
	offset = 0;
	linelen = tvb_find_line_end(tvb, 0, -1, &next_offset, FALSE);

	/* Find the first SP and skip the first token */
	token_2_start = tvb_find_guint8(tvb, 0, linelen, ' ') + 1;

	/* Work out 2nd token's length by finding next space */
	space_offset = tvb_find_guint8(tvb, token_2_start, linelen-token_2_start, ' ');
	token_2_len = space_offset - token_2_start;

	/* Transaction ID found store it for later use */
	transaction_id_str = tvb_get_ephemeral_string(tvb, token_2_start, token_2_len);

	/* Look for another space in this line to indicate a 4th token */
	token_3_start = space_offset + 1;
	space_offset = tvb_find_guint8(tvb, token_3_start,linelen-token_3_start, ' ');
	if ( space_offset == -1){
		/* 3rd token runs to the end of the line */
		token_3_len = linelen - token_3_start;
	}else{
		/* We have a fourth token */
		token_3_len = space_offset - token_3_start;
		token_4_start = space_offset + 1;
		token_4_len = linelen - token_4_start;
	}

	/*
	 * Yes, so this is either a msrp-request or msrp-response.
	 * To be a msrp-response, the second token must be
	 * a 3-digit number.
	 */
	is_msrp_response = FALSE;
	if (token_3_len == 3) {
			if (isdigit(tvb_get_guint8(tvb, token_3_start)) &&
			    isdigit(tvb_get_guint8(tvb, token_3_start + 1)) &&
			    isdigit(tvb_get_guint8(tvb, token_3_start + 2))) {
				is_msrp_response = TRUE;
			}
	}

	/* Make entries in Protocol column and Info column on summary display */
	col_set_str(pinfo->cinfo, COL_PROTOCOL, "MSRP");
	if (is_msrp_response){
		if (check_col(pinfo->cinfo, COL_INFO)) {
			col_add_fstr(pinfo->cinfo, COL_INFO, "Response: %s ",
					tvb_format_text(tvb, token_3_start, token_3_len));

			if (token_4_len )
				col_append_fstr(pinfo->cinfo, COL_INFO, "%s ",
					tvb_format_text(tvb, token_4_start, token_4_len));

			col_append_fstr(pinfo->cinfo, COL_INFO, "Transaction ID: %s",
					tvb_format_text(tvb, token_2_start, token_2_len));
		}
	}else{
		if (check_col(pinfo->cinfo, COL_INFO)) {
			proto_tree_add_text(tree, tvb, token_3_start, token_3_len,
					"Col %s L=%u", tvb_format_text(tvb, token_3_start, token_3_len),token_3_len);

			col_add_fstr(pinfo->cinfo, COL_INFO, "Request: %s ",
					tvb_format_text(tvb, token_3_start, token_3_len));

			col_append_fstr(pinfo->cinfo, COL_INFO, "Transaction ID: %s",
					tvb_format_text(tvb, token_2_start, token_2_len));
		}
	}

	/* Find the end line to be able to process the headers
	 * Note that in case of [content-stuff] headers and [content-stuff] is separated by CRLF
	 */

	offset = next_offset;
	end_line_offset = find_end_line(tvb,offset);
	/* TODO if -1 (No end line found, is returned do something) */
	end_line_len =  tvb_find_line_end(tvb, end_line_offset, -1, &next_offset, FALSE);
	message_end_offset = end_line_offset + end_line_len + 2;


	if (tree) {
		ti = proto_tree_add_item(tree, proto_msrp, tvb, 0, message_end_offset, FALSE);
		msrp_tree = proto_item_add_subtree(ti, ett_msrp);

		if (is_msrp_response){
			th = proto_tree_add_item(msrp_tree,hf_msrp_response_line,tvb,0,linelen,FALSE);
			reqresp_tree = proto_item_add_subtree(th, ett_msrp_reqresp);
			proto_tree_add_item(reqresp_tree,hf_msrp_transactionID,tvb,token_2_start,token_2_len,FALSE);
			proto_tree_add_uint(reqresp_tree,hf_msrp_status_code,tvb,token_3_start,token_3_len,
			                    atoi(tvb_get_ephemeral_string(tvb, token_3_start, token_3_len)));

		}else{
			th = proto_tree_add_item(msrp_tree,hf_msrp_request_line,tvb,0,linelen,FALSE);
			reqresp_tree = proto_item_add_subtree(th, ett_msrp_reqresp);
			proto_tree_add_item(reqresp_tree,hf_msrp_transactionID,tvb,token_2_start,token_2_len,FALSE);
			proto_tree_add_item(reqresp_tree,hf_msrp_method,tvb,token_3_start,token_3_len,FALSE);
		}

		/* Conversation setup info */
		if (global_msrp_show_setup_info)
		{
			show_setup_info(tvb, pinfo, msrp_tree);
		}

		/* Headers */
		msrp_headers_item = proto_tree_add_item(msrp_tree, hf_msrp_msg_hdr, tvb, offset,(end_line_offset - offset), FALSE);
		msrp_hdr_tree = proto_item_add_subtree(msrp_headers_item, ett_msrp_hdr);

		/*
		 * Process the headers
		 */
		while (tvb_reported_length_remaining(tvb, offset) > 0 && offset < end_line_offset  ) {
			/* 'desegment' is FALSE so will set next_offset to beyond the end of
			   the buffer if no line ending is found */
			linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
			if (linelen == 0) {
				/*
				 * This is a blank line separating the
				 * message header from the message body.
				 */
				have_body = TRUE;
				break;
			}
			line_end_offset = offset + linelen;
			colon_offset = tvb_find_guint8(tvb, offset, linelen, ':');
			if (colon_offset == -1) {
				/*
				 * Malformed header - no colon after the name.
				 */
				proto_tree_add_text(msrp_hdr_tree, tvb, offset,
					                next_offset - offset, "%s",
						            tvb_format_text(tvb, offset, linelen));
			} else {
				header_len = colon_offset - offset;
				hf_index = msrp_is_known_msrp_header(tvb, offset, header_len);

				if (hf_index == -1) {
					proto_tree_add_text(msrp_hdr_tree, tvb,
				                    offset, next_offset - offset, "%s",
				                    tvb_format_text(tvb, offset, linelen));
				} else {
					/*
					 * Skip whitespace after the colon.
					 */
					value_offset = colon_offset + 1;
					while (value_offset < line_end_offset &&
					       ((c = tvb_get_guint8(tvb, value_offset)) == ' ' ||
					         c == '\t'))
						value_offset++;
					/*
					 * Fetch the value.
					 */
					value_len = line_end_offset - value_offset;
					value = tvb_get_ephemeral_string(tvb, value_offset,
				                       value_len);

					/*
					 * Add it to the protocol tree,
					 * but display the line as is.
					 */
					msrp_element_item = proto_tree_add_string_format(msrp_hdr_tree,
				                   hf_header_array[hf_index], tvb,
				                   offset, next_offset - offset,
				                   value, "%s",
				                   tvb_format_text(tvb, offset, linelen));
					msrp_element_tree = proto_item_add_subtree( msrp_element_item, ett_msrp_element);

					switch ( hf_index ) {

						case MSRP_CONTENT_TYPE :
							content_type_len = value_len;
							semi_colon_offset = tvb_find_guint8(tvb, value_offset,linelen, ';');
							if ( semi_colon_offset != -1) {
								parameter_offset = semi_colon_offset +1;
								/*
								 * Skip whitespace after the semicolon.
								 */
								while (parameter_offset < line_end_offset
								       && ((c = tvb_get_guint8(tvb, parameter_offset)) == ' '
								         || c == '\t'))
									parameter_offset++;
								content_type_len = semi_colon_offset - value_offset;
								content_type_parameter_str_len = line_end_offset - parameter_offset;
								content_type_parameter_str = tvb_get_ephemeral_string(tvb,
										     parameter_offset, content_type_parameter_str_len);
							}
							media_type_str_lower_case = ascii_strdown_inplace(
                                                            (gchar *)tvb_get_ephemeral_string(tvb, value_offset, content_type_len));
							break;

						default:
							break;
					}
				}
			}
			offset = next_offset;
		}/* End while */

		if ( have_body ){
			/*
			 * There's a message body starting at "next_offset".
			 * Set the length of the header item.
			 */
			proto_item_set_end(msrp_headers_item, tvb, next_offset);

			/* Create new tree & tvb for data */
			next_tvb = tvb_new_subset_remaining(tvb, next_offset);
			ti = proto_tree_add_item(msrp_tree, hf_msrp_data, tvb,
			                         next_offset, -1, FALSE);
			msrp_data_tree = proto_item_add_subtree(ti, ett_msrp_data);

			/* give the content type parameters to sub dissectors */

			if ( media_type_str_lower_case != NULL ) {
				void *save_private_data = pinfo->private_data;
				pinfo->private_data = content_type_parameter_str;
				found_match = dissector_try_string(media_type_dissector_table,
			                                   media_type_str_lower_case,
			                                   next_tvb, pinfo,
			                                   msrp_data_tree);
				pinfo->private_data = save_private_data;
				/* If no match dump as text */
			}
			if ( found_match != TRUE )
			{
				offset = 0;
				while (tvb_offset_exists(next_tvb, offset)) {
					tvb_find_line_end(next_tvb, offset, -1, &next_offset, FALSE);
					linelen = next_offset - offset;
					proto_tree_add_text(msrp_data_tree, next_tvb, offset, linelen,
				                    "%s", tvb_format_text(next_tvb, offset, linelen));
					offset = next_offset;
				}/* end while */
			}

		}



		/* End line */
		ti = proto_tree_add_item(msrp_tree,hf_msrp_end_line,tvb,end_line_offset,end_line_len,FALSE);
		msrp_end_tree = proto_item_add_subtree(ti, ett_msrp_end_line);

		proto_tree_add_item(msrp_end_tree,hf_msrp_transactionID,tvb,end_line_offset + 7,token_2_len,FALSE);
		/* continuation-flag */
		proto_tree_add_item(msrp_end_tree,hf_msrp_cnt_flg,tvb,end_line_offset+end_line_len-1,1,FALSE);

		if (global_msrp_raw_text){
			ti = proto_tree_add_text(tree, tvb, 0, -1,"Message Session Relay Protocol(as raw text)");
			raw_tree = proto_item_add_subtree(ti, ett_msrp);
			tvb_raw_text_add(tvb,raw_tree);
		}

	}/* if tree */
	return message_end_offset;
	/*	return tvb_length(tvb); */

/* If this protocol has a sub-dissector call it here, see section 1.8 */
}
Example #8
0
int k12_open(wtap *wth, int *err, gchar **err_info) {
    k12_src_desc_t* rec;
    guint8 header_buffer[0x200];
    guint8* read_buffer;
    guint32 type;
    long offset;
    long len;
    guint port_type;
    guint32 rec_len;
    guint32 hwpart_len;
    guint32 name_len;
    guint32 stack_len;
    guint i;
    k12_t* file_data;

#ifdef DEBUG_K12
    gchar* env_level = getenv("K12_DEBUG_LEVEL");
    env_file = getenv("K12_DEBUG_FILENAME");
    if ( env_file ) {
        dbg_out = ws_fopen(env_file,"w");
        if (dbg_out == NULL) {
            dbg_out = stderr;
            K12_DBG(1,("unable to open K12 DEBUG FILENAME for writing!  Logging to standard error"));
        }
    }
    else
        dbg_out = stderr;
    if ( env_level ) debug_level = (unsigned int)strtoul(env_level,NULL,10);
    K12_DBG(1,("k12_open: ENTER debug_level=%u",debug_level));
#endif

    if ( file_read(header_buffer,0x200,wth->fh) != 0x200 ) {
        K12_DBG(1,("k12_open: FILE HEADER TOO SHORT OR READ ERROR"));
        *err = file_error(wth->fh, err_info);
        if (*err != 0 && *err != WTAP_ERR_SHORT_READ) {
            return -1;
        }
        return 0;
    } else {
        if ( memcmp(header_buffer,k12_file_magic,8) != 0 ) {
            K12_DBG(1,("k12_open: BAD MAGIC"));
            return 0;
        }
    }

    offset = 0x200;

    file_data = new_k12_file_data();

    file_data->file_len = pntoh32( header_buffer + 0x8);
    file_data->num_of_records = pntoh32( header_buffer + 0xC );

    K12_DBG(5,("k12_open: FILE_HEADER OK: offset=%x file_len=%i records=%i",
               offset,
               file_data->file_len,
               file_data->num_of_records ));

    do {

        len = get_record(file_data, wth->fh, offset, FALSE, err, err_info);

        if ( len < 0 ) {
            K12_DBG(1,("k12_open: BAD HEADER RECORD",len));
            destroy_k12_file_data(file_data);
            return -1;
        }
        if (len == 0) {
            K12_DBG(1,("k12_open: BAD HEADER RECORD",len));
            *err = WTAP_ERR_SHORT_READ;
            destroy_k12_file_data(file_data);
            return -1;
        }

        if (len == 0) {
            K12_DBG(1,("k12_open: BAD HEADER RECORD",len));
            *err = WTAP_ERR_SHORT_READ;
            destroy_k12_file_data(file_data);
            return -1;
        }

        read_buffer = file_data->seq_read_buff;

        rec_len = pntoh32( read_buffer + K12_RECORD_LEN );
        if (rec_len < K12_RECORD_TYPE + 4) {
            /* Record isn't long enough to have a type field */
            *err = WTAP_ERR_BAD_FILE;
            *err_info = g_strdup_printf("k12_open: record length %u < %u",
                                        rec_len, K12_RECORD_TYPE + 4);
            return -1;
        }
        type = pntoh32( read_buffer + K12_RECORD_TYPE );

        if ( (type & K12_MASK_PACKET) == K12_REC_PACKET ||
                (type & K12_MASK_PACKET) == K12_REC_D0020) {
            /*
             * we are at the first packet record, rewind and leave.
             */
            if (file_seek(wth->fh, offset, SEEK_SET, err) == -1) {
                destroy_k12_file_data(file_data);
                return -1;
            }
            K12_DBG(5,("k12_open: FIRST PACKET offset=%x",offset));
            break;
        } else if (type == K12_REC_SRCDSC || type == K12_REC_SRCDSC2 ) {
            rec = g_new0(k12_src_desc_t,1);

            if (rec_len < K12_SRCDESC_HWPART) {
                /*
                 * Record isn't long enough to have the fixed-length portion
                 * of the source descriptor field.
                 */
                *err = WTAP_ERR_BAD_FILE;
                *err_info = g_strdup_printf("k12_open: source descriptor record length %u < %u",
                                            rec_len, K12_SRCDESC_HWPART);
                destroy_k12_file_data(file_data);
                g_free(rec);
                return -1;
            }
            port_type = read_buffer[K12_SRCDESC_PORT_TYPE];
            hwpart_len = pntoh16( read_buffer + K12_SRCDESC_HWPARTLEN );
            name_len = pntoh16( read_buffer + K12_SRCDESC_NAMELEN );
            stack_len = pntoh16( read_buffer + K12_SRCDESC_STACKLEN );

            rec->input = pntoh32( read_buffer + K12_RECORD_SRC_ID );

            K12_DBG(5,("k12_open: INTERFACE RECORD offset=%x interface=%x",offset,rec->input));

            if (name_len == 0) {
                K12_DBG(5,("k12_open: failed (name_len == 0 in source description"));
                destroy_k12_file_data(file_data);
                g_free(rec);
                return 0;
            }
            if (stack_len == 0) {
                K12_DBG(5,("k12_open: failed (stack_len == 0 in source description"));
                destroy_k12_file_data(file_data);
                g_free(rec);
                return 0;
            }
            if (rec_len < K12_SRCDESC_HWPART + hwpart_len + name_len + stack_len) {
                /*
                 * Record isn't long enough to have the full source descriptor
                 * field, including the variable-length parts.
                 */
                *err = WTAP_ERR_BAD_FILE;
                *err_info = g_strdup_printf("k12_open: source descriptor record length %u < %u (%u + %u + %u + %u)",
                                            rec_len,
                                            K12_SRCDESC_HWPART + hwpart_len + name_len + stack_len,
                                            K12_SRCDESC_HWPART, hwpart_len, name_len, stack_len);
                destroy_k12_file_data(file_data);
                g_free(rec);
                return -1;
            }

            if (hwpart_len) {
                if (hwpart_len < 4) {
                    /* Hardware part isn't long enough to have a type field */
                    *err = WTAP_ERR_BAD_FILE;
                    *err_info = g_strdup_printf("k12_open: source descriptor hardware part length %u < 4",
                                                hwpart_len);
                    destroy_k12_file_data(file_data);
                    g_free(rec);
                    return -1;
                }
                switch(( rec->input_type = pntoh32( read_buffer + K12_SRCDESC_HWPART + K12_SRCDESC_HWPARTTYPE ) )) {
                case K12_PORT_DS0S:
                    /* This appears to be variable-length */
                    rec->input_info.ds0mask = 0x00000000;
                    if (hwpart_len > K12_SRCDESC_DS0_MASK) {
                        for (i = 0; i < hwpart_len - K12_SRCDESC_DS0_MASK; i++) {
                            rec->input_info.ds0mask |= ( *(read_buffer + K12_SRCDESC_HWPART + K12_SRCDESC_DS0_MASK + i) == 0xff ) ? 0x1<<(31-i) : 0x0;
                        }
                    }
                    break;
                case K12_PORT_ATMPVC:
                    if (hwpart_len < K12_SRCDESC_ATM_VCI + 2) {
                        /* Hardware part isn't long enough to have ATM information */
                        *err = WTAP_ERR_BAD_FILE;
                        *err_info = g_strdup_printf("k12_open: source descriptor hardware part length %u < %u",
                                                    hwpart_len,
                                                    K12_SRCDESC_ATM_VCI + 2);
                        destroy_k12_file_data(file_data);
                        g_free(rec);
                        return -1;
                    }

                    rec->input_info.atm.vp = pntoh16( read_buffer + K12_SRCDESC_HWPART + K12_SRCDESC_ATM_VPI );
                    rec->input_info.atm.vc = pntoh16( read_buffer + K12_SRCDESC_HWPART + K12_SRCDESC_ATM_VCI );
                    break;
                default:
                    break;
                }
            } else {
                /* Record viewer generated files don't have this information */
                if (port_type >= 0x14
                        && port_type <= 0x17) {
                    /* For ATM2_E1DS1, ATM2_E3DS3,
                       ATM2_STM1EL and ATM2_STM1OP */
                    rec->input_type = K12_PORT_ATMPVC;
                    rec->input_info.atm.vp = 0;
                    rec->input_info.atm.vc = 0;
                }
            }

            if (read_buffer[K12_SRCDESC_HWPART + hwpart_len + name_len - 1] != '\0') {
                *err = WTAP_ERR_BAD_FILE;
                *err_info = g_strdup("k12_open: source descriptor record contains non-null-terminated link-layer name");
                destroy_k12_file_data(file_data);
                g_free(rec);
                return -1;
            }
            if (read_buffer[K12_SRCDESC_HWPART + hwpart_len + name_len + stack_len - 1] != '\0') {
                *err = WTAP_ERR_BAD_FILE;
                *err_info = g_strdup("k12_open: source descriptor record contains non-null-terminated stack path");
                destroy_k12_file_data(file_data);
                g_free(rec);
                return -1;
            }
            rec->input_name = (gchar *)g_memdup(read_buffer + K12_SRCDESC_HWPART + hwpart_len, name_len);
            rec->stack_file = (gchar *)g_memdup(read_buffer + K12_SRCDESC_HWPART + hwpart_len + name_len, stack_len);

            ascii_strdown_inplace (rec->stack_file);

            g_hash_table_insert(file_data->src_by_id,GUINT_TO_POINTER(rec->input),rec);
            g_hash_table_insert(file_data->src_by_name,rec->stack_file,rec);

            offset += len;
            continue;
        } else if (type == K12_REC_STK_FILE) {
            K12_DBG(1,("k12_open: K12_REC_STK_FILE"));
            K12_DBG(1,("Field 1: 0x%08x",pntoh32( read_buffer + 0x08 )));
            K12_DBG(1,("Field 2: 0x%08x",pntoh32( read_buffer + 0x0c )));
            K12_ASCII_DUMP(1, read_buffer, rec_len, 0x10);

            offset += len;
            continue;
        } else {
            K12_DBG(1,("k12_open: RECORD TYPE 0x%08x",type));
            offset += len;
            continue;
        }
    } while(1);

    wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_K12;
    wth->file_encap = WTAP_ENCAP_K12;
    wth->snapshot_length = 0;
    wth->subtype_read = k12_read;
    wth->subtype_seek_read = k12_seek_read;
    wth->subtype_close = k12_close;
    wth->priv = (void *)file_data;
    wth->tsprecision = WTAP_FILE_TSPREC_NSEC;

    return 1;
}