/*
 * Dissect a standard (reliable) ts2 packet, reassembling if required.
 */
static void ts2_standard_dissect(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ts2_tree, ts2_conversation *conversation_data)
{
    guint8 save_fragmented;
    tvbuff_t *new_tvb, *next_tvb;
    fragment_data *frag_msg ;
    guint16 fragment_number;
    ts2_frag *frag;
    gboolean outoforder;

    guint16 type = tvb_get_letohs(tvb, 2);
    /*guint16 class = tvb_get_letohs(tvb, 0);*/
    proto_tree_add_item(ts2_tree, hf_ts2_seqnum, tvb, 12, 4, TRUE);

    /* XXX: Following fragmentation stuff should be separate from the GUI stuff ??    */
    /* Get our stored fragmentation data or create one! */
    if ( ! ( frag = p_get_proto_data(pinfo->fd, proto_ts2) ) ) {
        frag = se_alloc(sizeof(ts2_frag));
        frag->frag_num=0;
    }

    /* decide if the packet is server to client or client to server
     * then check its fragmentation
     */
    if(!(pinfo->fd->flags.visited))
    {
        if(conversation_data->server_port == pinfo->srcport)
        {
            frag->fragmented = ts2_standard_find_fragments(tvb, &conversation_data->last_inorder_server_frame, &conversation_data->server_frag_size, &conversation_data->server_frag_num, &outoforder);
            frag->frag_num=conversation_data->server_frag_num;
            frag->frag_size=conversation_data->server_frag_size;
        }
        else
        {

            frag->fragmented = ts2_standard_find_fragments(tvb, &conversation_data->last_inorder_client_frame, &conversation_data->client_frag_size, &conversation_data->client_frag_num, &outoforder);
            frag->frag_num=conversation_data->client_frag_num;
            frag->frag_size=conversation_data->client_frag_size;
        }
        frag->outoforder=outoforder;
        p_add_proto_data(pinfo->fd, proto_ts2, frag);
    }

    /* Get our stored fragmentation data */
    frag = p_get_proto_data(pinfo->fd, proto_ts2);

    proto_tree_add_item(ts2_tree, hf_ts2_resend_count, tvb, 16, 2, TRUE);
    proto_tree_add_item(ts2_tree, hf_ts2_fragmentnumber, tvb, 18, 2, TRUE);
    ts2_add_checked_crc32(ts2_tree, hf_ts2_crc32, tvb, 20, tvb_get_letohl(tvb, 20));

    /* Reassemble the packet if its fragmented */
    new_tvb = NULL;
    if(frag->fragmented)
    {
        save_fragmented = pinfo->fragmented;
        frag_msg = NULL;
        pinfo->fragmented = TRUE;
        fragment_number = tvb_get_letohs(tvb, 18);
        frag_msg = fragment_add_seq_check(tvb, 24, pinfo, type,	msg_fragment_table, msg_reassembled_table, frag->frag_num, tvb_length_remaining(tvb, 24), fragment_number);
        new_tvb = process_reassembled_data(tvb, 24, pinfo,"Reassembled Message", frag_msg, &msg_frag_items, NULL, ts2_tree);
        if (frag_msg)
        {   /* Reassembled */
            if (check_col(pinfo->cinfo, COL_INFO)) col_append_str(pinfo->cinfo, COL_INFO, " (Message Reassembled)");
        }
        else
        {   /* Not last packet of reassembled Short Message */
            if (check_col(pinfo->cinfo, COL_INFO))col_append_fstr(pinfo->cinfo, COL_INFO," (Message fragment %u)", frag->frag_num);
        }
        if (new_tvb)
            next_tvb = new_tvb;
        else
            next_tvb = tvb_new_subset_remaining(tvb, 24);
        pinfo->fragmented = save_fragmented;
    }
    else
        next_tvb = tvb_new_subset_remaining(tvb, 24);

    /* If we have a full packet now dissect it */
    if((new_tvb || !frag->fragmented) && !frag->outoforder)
    {
        switch(type)
        {
        case TS2T_LOGINPART2:
            ts2_parse_loginpart2(next_tvb, ts2_tree);
            break;
        case TS2T_CHANNELLIST:
            ts2_parse_channellist(next_tvb, ts2_tree);
            break;
        case TS2T_PLAYERLIST:
            ts2_parse_playerlist(next_tvb, ts2_tree);
            break;
        case TS2T_NEWPLAYERJOINED:
            ts2_parse_newplayerjoined(next_tvb, ts2_tree);
            break;
        case TS2T_KNOWNPLAYERUPDATE:
            ts2_parse_knownplayerupdate(next_tvb, ts2_tree);
            break;
        case TS2T_PLAYERLEFT:
            ts2_parse_playerleft(next_tvb, ts2_tree);
            break;
        case TS2T_PLAYERKICKED:
            ts2_parse_playerleft(next_tvb, ts2_tree);
            break;
        case TS2T_LOGINEND:
            ts2_parse_loginend(next_tvb, ts2_tree);
            break;
        case TS2T_CHANGESTATUS:
            ts2_parse_changestatus(next_tvb, ts2_tree);
            break;
        case TS2T_SWITCHCHANNEL:
            ts2_parse_switchchannel(next_tvb, ts2_tree);
            break;
        case TS2T_CHANNELCHANGE:
            ts2_parse_channelchange(next_tvb, ts2_tree);
            break;
        }
    }
    /* The packet is out of order, update the cinfo and ignore the packet */
    if(frag->outoforder)
        if (check_col(pinfo->cinfo, COL_INFO)) col_append_str(pinfo->cinfo, COL_INFO, " (Out Of Order, ignored)");
}
Esempio n. 2
0
/* Dissect a TS2 packet */
static void dissect_ts2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
	ts2_conversation *conversation_data;
	guint16 type = tvb_get_letohs(tvb, 2);
	guint16 klass = tvb_get_letohs(tvb, 0);

	conversation_data = ts2_get_conversation(pinfo);

	col_set_str(pinfo->cinfo, COL_PROTOCOL, "TS2");

	if (check_col(pinfo->cinfo, COL_INFO)) {
		if(klass==TS2C_ACK)
			col_add_fstr(pinfo->cinfo, COL_INFO, "Class: %s", val_to_str(klass, classnames, "Unknown (0x%02x)"));
		else
			col_add_fstr(pinfo->cinfo, COL_INFO, "Type: %s, Class: %s", val_to_str(type, typenames, "Unknown (0x%02x)"), val_to_str(klass, classnames, "Unknown (0x%02x)"));
	}

	/* XXX: We need to do all the non GUI stuff whether or not if(tree) */
        /*      Do only once by checking visited ?                          */
        /*      ToDo: Rewrite ??                                            */
	if (!tree) {
		switch(klass) {
			case TS2C_CONNECTION:
				switch(type) {
					case TS2T_LOGINREQUEST:
						conversation_data->server_port=pinfo->destport;
						conversation_data->server_addr=pinfo->dst;
						break;
				}
				break;
			case TS2C_STANDARD:
				ts2_standard_dissect(tvb, pinfo, tree, conversation_data);
				break;
		}
	}

	if (tree) { /* we are being asked for details */
		proto_item *ti = NULL;
		proto_tree *ts2_tree = NULL;

		ti = proto_tree_add_item(tree, proto_ts2, tvb, 0, -1, ENC_NA);
		ts2_tree = proto_item_add_subtree(ti, ett_ts2);

		proto_tree_add_item(ts2_tree, hf_ts2_class, tvb, 0, 2, ENC_LITTLE_ENDIAN);
		if(klass==TS2C_ACK)
			proto_tree_add_item(ts2_tree, hf_ts2_resend_count, tvb, 2, 2, ENC_LITTLE_ENDIAN);
		else
			proto_tree_add_item(ts2_tree, hf_ts2_type, tvb, 2, 2, ENC_LITTLE_ENDIAN);

		proto_tree_add_item(ts2_tree, hf_ts2_sessionkey, tvb, 4, 4, ENC_LITTLE_ENDIAN);
		proto_tree_add_item(ts2_tree, hf_ts2_clientid, tvb, 8, 4, ENC_LITTLE_ENDIAN);
		switch(klass)
		{
			case TS2C_CONNECTION:
				proto_tree_add_item(ts2_tree, hf_ts2_seqnum, tvb, 12, 4, ENC_LITTLE_ENDIAN);
				ts2_add_checked_crc32(ts2_tree, hf_ts2_crc32, tvb, 16, tvb_get_letohl(tvb, 16));

				switch(type)
				{
					case TS2T_PING:
						break;
					case TS2T_PINGREPLY:
						proto_tree_add_item(ts2_tree, hf_ts2_ackto, tvb, 20, 4, ENC_LITTLE_ENDIAN);
						break;
					case TS2T_LOGINREQUEST:
						proto_tree_add_item(ts2_tree, hf_ts2_protocol_string, tvb, 20, 1, ENC_ASCII|ENC_NA);
						proto_tree_add_item(ts2_tree, hf_ts2_platform_string, tvb, 50, 1, ENC_ASCII|ENC_NA);
						proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, 80, 9, ENC_NA);
						proto_tree_add_item(ts2_tree, hf_ts2_registeredlogin, tvb, 90, 1, ENC_LITTLE_ENDIAN);
						proto_tree_add_item(ts2_tree, hf_ts2_name, tvb, 90, 1, ENC_ASCII|ENC_NA);
						proto_tree_add_item(ts2_tree, hf_ts2_password, tvb, 120, 1, ENC_ASCII|ENC_NA);
						proto_tree_add_item(ts2_tree, hf_ts2_nick, tvb, 150, 1, ENC_ASCII|ENC_NA);

						conversation_data->server_port=pinfo->destport;
						conversation_data->server_addr=pinfo->dst;

						break;
					case TS2T_LOGINREPLY:
						proto_tree_add_item(ts2_tree, hf_ts2_server_name, tvb, 20, 1, ENC_ASCII|ENC_NA);
						proto_tree_add_item(ts2_tree, hf_ts2_platform_string, tvb, 50, 1, ENC_ASCII|ENC_NA);
						proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, 80, 9, ENC_NA);
						proto_tree_add_item(ts2_tree, hf_ts2_badlogin, tvb, 89, 3, ENC_LITTLE_ENDIAN);
						proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, 92, 80, ENC_NA);
						proto_tree_add_item(ts2_tree, hf_ts2_sessionkey, tvb, 172, 4, ENC_LITTLE_ENDIAN);
						proto_tree_add_item(ts2_tree, hf_ts2_unknown, tvb, 178, 3, ENC_NA);
						proto_tree_add_item(ts2_tree, hf_ts2_server_welcome_message, tvb, 180, 1, ENC_ASCII|ENC_NA);
                                                break;
				}
				break;
			case TS2C_ACK:
				/* Ignore the type for ACK, it's always zero and clashes with CELP_5_1 */

				proto_tree_add_item(ts2_tree, hf_ts2_seqnum, tvb, 12, 4, ENC_LITTLE_ENDIAN);
				break;
			case TS2C_STANDARD:
				ts2_standard_dissect(tvb, pinfo, ts2_tree, conversation_data);
				break;
		}
	} /* if (tree) */
}