/* packet-sasp.c * Routines for sasp packet dissection * Copyright 2010, Venkateshwaran Dorai * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "config.h" #include #include #include #include #include "packet-tcp.h" /* forward reference */ void proto_register_sasp(void); void proto_reg_handoff_sasp(void); static dissector_handle_t sasp_handle; static void dissect_reg_req(tvbuff_t *tvb, proto_tree *tree, guint32 offset); static void dissect_dereg_req(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset); static void dissect_reg_rep(tvbuff_t *tvb, proto_tree *tree, guint32 offset); static void dissect_dereg_rep(tvbuff_t *tvb, proto_tree *tree, guint32 offset); static void dissect_sendwt(tvbuff_t *tvb, proto_tree *tree, guint32 offset); static void dissect_setmemstate_req(tvbuff_t *tvb, proto_tree *tree, guint32 offset); static void dissect_setmemstate_rep(tvbuff_t *tvb, proto_tree *tree, guint32 offset); static void dissect_setlbstate_req(tvbuff_t *tvb, proto_tree *tree, guint32 offset); static void dissect_setlbstate_rep(tvbuff_t *tvb, proto_tree *tree, guint32 offset); static void dissect_wt_req(tvbuff_t *tvb, proto_tree *tree, guint32 offset); static void dissect_wt_rep(tvbuff_t *tvb, proto_tree *tree, guint32 offset); static guint32 dissect_memdatacomp(tvbuff_t *tvb, proto_tree *tree, guint32 offset, proto_tree **mdct_p); static guint32 dissect_grpdatacomp(tvbuff_t *tvb, proto_tree *tree, guint32 offset); static guint32 dissect_grp_memdatacomp(tvbuff_t *tvb, proto_tree *tree, guint32 offset); static guint32 dissect_grp_memstatedatacomp(tvbuff_t *tvb, proto_tree *tree, guint32 offset); static guint32 dissect_memstatedatacomp(tvbuff_t *tvb, proto_tree *tree, guint32 offset); static guint32 dissect_weight_entry_data_comp(tvbuff_t *tvb, proto_tree *pay_load, guint32 offset); static guint32 dissect_grp_wt_entry_datacomp(tvbuff_t *tvb, proto_tree *tree, guint32 offset); /* Initialize the protocol and registered fields */ static int proto_sasp = -1; static int hf_sasp_type = -1; static int hf_sasp_length = -1; static int hf_sasp_vrsn = -1; static int hf_msg_len = -1; static int hf_msg_id = -1; static int hf_msg_type = -1; /*reg reply*/ static int hf_sasp_reg_rep_rcode = -1; static int hf_sasp_reg_rep_sz = -1; /*reg req*/ static int hf_sasp_reg_req_sz = -1; static int hf_reg_req_lbflag = -1; static int hf_sasp_gmd_cnt = -1; /*dereg req*/ static int hf_sasp_dereg_req_sz = -1; static int hf_dereg_req_lbflag = -1; /* static int hf_dereg_req_reason = -1; */ static int hf_dereg_req_reason_flag = -1; /*dereg reply*/ static int hf_sasp_dereg_rep_rcode = -1; static int hf_sasp_dereg_rep_sz = -1; /*send wt*/ static int hf_sasp_sendwt_gwedcnt = -1; static int hf_sasp_sendwt_sz = -1; /*setmemstate req*/ static int hf_sasp_setmemstate_req_sz = -1; static int hf_setmemstate_req_lbflag = -1; /*static int hf_sasp_setmemstate_req_data = -1;*/ static int hf_sasp_setmemstate_req_gmsd_cnt = -1; /*setmemstate reply*/ /* static int hf_sasp_setmemstate_rep = -1; */ static int hf_sasp_setmemstate_rep_rcode = -1; static int hf_sasp_setmemstate_rep_sz = -1; /*mem data comp */ static int hf_sasp_memdatacomp_type = -1; static int hf_sasp_memdatacomp_sz = -1; static int hf_sasp_memdatacomp_protocol = -1; static int hf_sasp_memdatacomp_port = -1; static int hf_sasp_memdatacomp_ip = -1; static int hf_sasp_memdatacomp_lab_len = -1; static int hf_sasp_memdatacomp_label = -1; /*grp data comp */ static int hf_sasp_grpdatacomp = -1; static int hf_sasp_grpdatacomp_sz = -1; static int hf_sasp_grpdatacomp_LB_uid_len = -1; static int hf_sasp_grpdatacomp_LB_uid = -1; static int hf_sasp_grpdatacomp_grp_name_len = -1; static int hf_sasp_grpdatacomp_grp_name = -1; /*grp mem data comp */ static int hf_sasp_grp_memdatacomp = -1; static int hf_sasp_grp_memdatacomp_sz = -1; static int hf_sasp_grp_memdatacomp_cnt = -1; /*weight req*/ static int hf_sasp_wt_req_sz = -1; static int hf_sasp_wt_req_gd_cnt = -1; /*weight rep*/ static int hf_sasp_wt_rep_sz = -1; static int hf_sasp_wt_rep_rcode = -1; static int hf_sasp_wt_rep_interval = -1; static int hf_sasp_wt_rep_gwed_cnt = -1; /*setlbstate req*/ static int hf_sasp_setlbstate_req_sz = -1; static int hf_sasp_setlbstate_req_LB_uid_len = -1; static int hf_sasp_setlbstate_req_LB_uid = -1; static int hf_sasp_setlbstate_req_LB_health = -1; /*static int hf_sasp_setlbstate_req_LB_flag = -1;*/ /* static int hf_lbstate_flag = -1; */ static int hf_sasp_pushflag = -1; static int hf_sasp_trustflag = -1; static int hf_sasp_nochangeflag = -1; /*setlbstate reply*/ /* static int hf_sasp_setlbstate_rep = -1; */ static int hf_sasp_setlbstate_rep_rcode = -1; static int hf_sasp_setlbstate_rep_sz = -1; /*grp mem state data*/ static int hf_sasp_grp_memstatedatacomp = -1; static int hf_sasp_grp_memstatedatacomp_sz = -1; static int hf_sasp_grp_memstatedatacomp_cnt = -1; /*mem state data comp*/ static int hf_sasp_memstatedatacomp_instance = -1; static int hf_sasp_memstatedatacomp_sz = -1; static int hf_sasp_memstatedatacomp_state = -1; static int hf_sasp_memstatedatacomp_quiesce_flag = -1; /*wt entry dat comp*/ static int hf_sasp_weight_entry_data_comp_type = -1; static int hf_sasp_weight_entry_data_comp_sz = -1; static int hf_sasp_weight_entry_data_comp_state = -1; /* static int hf_wtstate_flag = -1; */ static int hf_sasp_wed_contactsuccess_flag = -1; static int hf_sasp_wed_quiesce_flag = -1; static int hf_sasp_wed_registration_flag = -1; static int hf_sasp_wed_confident_flag = -1; static int hf_sasp_weight_entry_data_comp_weight = -1; /*grp wt entry data comp */ static int hf_sasp_grp_wt_entry_datacomp_type = -1; static int hf_sasp_grp_wt_entry_datacomp_sz = -1; static int hf_sasp_grp_wt_entry_datacomp_cnt = -1; /* Initialize the subtree pointers */ static gint ett_sasp_data = -1; static gint ett_sasp_header = -1; static gint ett_sasp_msg = -1; static gint ett_sasp_payload = -1; static gint ett_sasp_reg_req = -1; static gint ett_sasp_reg_rep = -1; static gint ett_sasp_reg_req_sz = -1; static gint ett_sasp_dereg_req_sz= -1; static gint ett_sasp_dereg_rep = -1; static gint ett_sasp_sendwt = -1; static gint ett_sasp_setmemstate_rep = -1; static gint ett_sasp_memdatacomp = -1; static gint ett_sasp_grpdatacomp = -1; static gint ett_sasp_grp_memdatacomp = -1; static gint ett_sasp_setlbstate_req = -1; static gint ett_sasp_setlbstate_rep = -1; static gint ett_sasp_getwt= -1; static gint ett_sasp_setmemstate_req = -1; static gint ett_setlbstate_req_lbflag = -1; static gint ett_sasp_grp_memstatedatacomp = -1; static gint ett_sasp_memstatedatacomp = -1; /*static gint ett_dereg_req_reason_flag = -1;*/ static gint ett_sasp_grp_wt_entry_datacomp = -1; static gint ett_sasp_weight_entry_data_comp = -1; static gint ett_wt_entry_data_flag = -1; static gint ett_sasp_wt_rep = -1; static expert_field ei_msg_type_invalid = EI_INIT; /* desegmentation of SASP over TCP */ static gboolean sasp_desegment = TRUE; static const value_string msg_table[] = { { 0x1010, "Registration Request" }, { 0x1015, "Registration Reply"}, { 0x1020, "DeRegistration Request"}, { 0x1025, "DeRegistration Reply"}, { 0x1030, "Get Weights Request"}, { 0x1035, "Get Weights Reply" }, { 0x1040, "Send Weights"}, { 0x1050, "Set LB State Request"}, { 0x1055, "Set LB State Reply"}, { 0x1060, "Set Member State Request"}, { 0x1065, "Set Member State Reply"}, { 0x3010, "Member Data Component"}, { 0x3011, "Group Data Component"}, { 0x3012, "Weight Entry Data Component"}, { 0x3013, "Member State Instance"}, { 0x4010, "Group of Member Data"}, { 0x4011, "Group of Weight Entry Data" }, { 0x4012, "Group of Member State Data" }, { 0, NULL } }; static value_string_ext msg_table_ext = VALUE_STRING_EXT_INIT(msg_table); static const value_string protocol_table[] = { { 0x06, "TCP" }, { 0x11, "UDP" }, { 0, NULL } }; static const value_string lbstate_healthtable[] = { { 0x00, "Least Healthy" }, { 0x7f, "Most Healthy" }, { 0, NULL } }; static const value_string reg_reply_response_code[] = { { 0x00, "Successful" }, { 0x10, "Message not understood" }, { 0x11, "GWM will not accept this message from the sender" }, { 0x40, "Member already registered" }, { 0x44, "Duplicate Member in Request" }, { 0x45, "Invalid Group (determined by the GWM)"}, { 0x50, "Invalid Group Name Size (size == 0)"}, { 0x51, "Invalid LB uid Size (size == 0 or > max)"}, { 0x61, "Member is registering itself, but LB hasn't yet contacted the GWM." " This registration will not be processed."}, { 0, NULL } }; static const value_string dereg_reply_response_code[] = { { 0x00, "Successful" }, { 0x10, "Message not understood" }, { 0x11, "GWM will not accept this message from the sender" }, { 0x41, "Application or System not registered" }, { 0x42, "Unknown Group Name" }, { 0x43, "Unknown LB uid" }, { 0x44, "Duplicate Member in Request"}, { 0x46, "Duplicate Group in Request (for remove all members/groups requests)"}, { 0x51, "Invalid LB uid Size (size == 0 or > max)"}, { 0x61, "Member is deregistering itself, but LB hasn't yet contacted the GWM." " This deregistration will not be processed."}, { 0, NULL } }; static const value_string get_weights_reply_response_code[] = { { 0x00, "Successful" }, { 0x10, "Message not understood" }, { 0x11, "GWM will not accept this message from the sender" }, { 0x42, "Unknown Group Name" }, { 0x43, "Unknown LB uid" }, { 0x46, "Duplicate Group in Request"}, { 0x51, "Invalid LB uid Size (size == 0 or > max)"}, { 0, NULL } }; static const value_string set_lb_state_reply_response_code[] = { { 0x00, "Successful" }, { 0x10, "Message not understood" }, { 0x11, "GWM will not accept this message from the sender" }, { 0x51, "Invalid LB uid Size (size == 0 or > max)"}, { 0, NULL } }; static const value_string set_mem_state_reply_response_code[] = { { 0x00, "Successful" }, { 0x10, "Message not understood" }, { 0x11, "GWM will not accept this message from the sender" }, { 0x41, "Application or System not registered" }, { 0x42, "Unknown Group Name" }, { 0x43, "Unknown LB uid" }, { 0x44, "Duplicate Member in Request"}, { 0x46, "Duplicate Group in Request (for remove all members/groups requests)"}, { 0x50, "Invalid Group Name Size (size == 0)"}, { 0x51, "Invalid LB uid Size (size == 0 or > max)"}, { 0, NULL } }; #define SASP_GLOBAL_PORT 3860 #define SASP_MIN_PACKET_LEN 13 #define SASP_DEREG_REQ_REASON_LEARNED 0x01 #define SASP_DEREG_REQ_NOREASON_FLAG 0x00 #define SASP_HDR_TYPE 0x2010 #define SASP_WED_CONTACT_SUCCESS_FLAG 0x01 #define SASP_WED_QUIESCE_FLAG 0x02 #define SASP_WED_REG_FLAG 0x04 #define SASP_WED_CONF_FLAG 0x08 #define SASP_PUSH_FLAG 0x01 #define SASP_TRUST_FLAG 0x02 #define SASP_NOCHANGE_FLAG 0x04 #define SASP_QUIESCE_FLAG 0x01 static guint get_sasp_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_) { /* Get the length of the SASP packet. */ return tvb_get_ntohl(tvb, offset + 5); } /* Called from tcp_dissect_pdus with a complete SASP pdu */ static int dissect_sasp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) { /* Set up structures needed to add the protocol subtree and manage it */ proto_item *ti; proto_item *hti; proto_item *mti; proto_tree *sasp_tree; proto_tree *msg_tree; proto_tree *pay_load; guint16 msg_type; guint16 hdr_type; guint32 offset = 0; /*protocol is being displayed*/ col_set_str(pinfo->cinfo, COL_PROTOCOL, "SASP"); col_clear(pinfo->cinfo, COL_INFO); ti = proto_tree_add_item(tree, proto_sasp, tvb, offset, -1, ENC_NA); sasp_tree = proto_item_add_subtree(ti, ett_sasp_header); hdr_type = tvb_get_ntohs(tvb, offset); hti = proto_tree_add_uint_format_value(sasp_tree, hf_sasp_type, tvb, offset, 2, hdr_type, "%s", (hdr_type == SASP_HDR_TYPE) ? "SASP" : "[Invalid]"); if (hdr_type != SASP_HDR_TYPE) { expert_add_info_format(pinfo, hti, &ei_msg_type_invalid, "Invalid SASP Header Type [0x%04x]", hdr_type); /* XXX: The folowing should actually happen automatically ? */ col_set_str(pinfo->cinfo, COL_INFO, "[Malformed: Invalid SASP Header Type]"); return tvb_reported_length(tvb); } offset += 2; /*length*/ proto_tree_add_item(sasp_tree, hf_sasp_length, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; /*Header Version */ proto_tree_add_item(sasp_tree, hf_sasp_vrsn, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; /*Message*/ msg_tree = proto_item_add_subtree(ti, ett_sasp_msg); /*Message Len*/ proto_tree_add_item(msg_tree, hf_msg_len, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; /*Message Id*/ proto_tree_add_item(msg_tree, hf_msg_id, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; /*Message Type*/ msg_type = tvb_get_ntohs(tvb, offset); mti = proto_tree_add_item(msg_tree, hf_msg_type, tvb, offset, 2, ENC_BIG_ENDIAN); pay_load = proto_item_add_subtree(ti, ett_sasp_payload); offset += 2; switch(msg_type) { case 0x1010: /* Registration Request */ col_set_str(pinfo->cinfo, COL_INFO, "Registration Request"); dissect_reg_req(tvb, pay_load, offset); break; case 0x1015: /* Registration Reply */ col_set_str(pinfo->cinfo, COL_INFO, "Registration Reply"); dissect_reg_rep(tvb, pay_load, offset); break; case 0x1020: /* Deregistration Request */ col_set_str(pinfo->cinfo, COL_INFO, "Deregistration Request"); dissect_dereg_req(tvb, pinfo, pay_load, offset); break; case 0x1025: /* Deregistration Reply */ col_set_str(pinfo->cinfo, COL_INFO, "Deregistration Reply"); dissect_dereg_rep(tvb, pay_load, offset); break; case 0x1030: /* Get Weights Request */ col_set_str(pinfo->cinfo, COL_INFO, "Get Weights Request"); dissect_wt_req(tvb, pay_load, offset); break; case 0x1035: /* Get Weights Response */ col_set_str(pinfo->cinfo, COL_INFO, "Get Weights Response"); dissect_wt_rep(tvb, pay_load, offset); break; case 0x1040: /* Send Weights Request */ col_set_str(pinfo->cinfo, COL_INFO, "Send Weights Request"); dissect_sendwt(tvb, pay_load, offset); break; case 0x1050: /* Set LB State Request */ col_set_str(pinfo->cinfo, COL_INFO, "Set LB State Request"); dissect_setlbstate_req(tvb, pay_load, offset); break; case 0x1055: /* Set LB state Reply */ col_set_str(pinfo->cinfo, COL_INFO, "Set LB State Reply"); dissect_setlbstate_rep(tvb, pay_load, offset); break; case 0x1060: /* Set Member State Request*/ col_set_str(pinfo->cinfo, COL_INFO, "Set Member State Request"); dissect_setmemstate_req(tvb, pay_load, offset); break; case 0x1065: /* Set Member State Reply */ col_set_str(pinfo->cinfo, COL_INFO, "Set Member State Reply"); dissect_setmemstate_rep(tvb, pay_load, offset); break; default: /* Unknown SASP Message Type */ col_add_fstr(pinfo->cinfo, COL_INFO, "[Malformed: Unknown Message Type [0x%04x]", msg_type); expert_add_info_format(pinfo, mti, &ei_msg_type_invalid, "Unknown SASP Message Type: 0x%4x", msg_type); break; } return tvb_reported_length(tvb); } static int dissect_sasp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) { tcp_dissect_pdus(tvb, pinfo, tree, sasp_desegment, SASP_MIN_PACKET_LEN, get_sasp_pdu_len, dissect_sasp_pdu, data); return tvb_reported_length(tvb); } static void dissect_reg_req(tvbuff_t *tvb, proto_tree *pay_load, guint32 offset) { proto_tree *reg_req_data; guint16 gmd_cnt, i; reg_req_data = proto_tree_add_subtree(pay_load, tvb, offset, -1, ett_sasp_reg_req_sz, NULL, "Reg Request"); /* Reg Req Size */ proto_tree_add_item(reg_req_data, hf_sasp_reg_req_sz, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; /* Reg Req LB Flag */ proto_tree_add_item(reg_req_data, hf_reg_req_lbflag, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; gmd_cnt = tvb_get_ntohs(tvb, offset); /* Group MEM Data Count */ proto_tree_add_item(reg_req_data, hf_sasp_gmd_cnt, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; for (i=0; ipool); static const gchar *fstr[] = {"No Reason", "Learned & Purposeful" }; dereg_req_data = proto_tree_add_subtree(pay_load, tvb, offset, -1, ett_sasp_dereg_req_sz, NULL, "DeReg Request"); /* Size */ proto_tree_add_item(dereg_req_data, hf_sasp_dereg_req_sz, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; /* LB Flag */ proto_tree_add_item(dereg_req_data, hf_dereg_req_lbflag, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; /* Reason */ wmem_strbuf_truncate(reasonflags_strbuf, 0); reason_flag = tvb_get_guint8(tvb, offset); if ((reason_flag & SASP_DEREG_REQ_REASON_LEARNED) == 0) wmem_strbuf_append_printf(reasonflags_strbuf, "%s%s", first_flag ? "" : ", ", fstr[0]); else wmem_strbuf_append_printf(reasonflags_strbuf, "%s%s", first_flag ? "" : ", ", fstr[1]); first_flag = FALSE; /*dereg_req_reason_flag =*/ proto_tree_add_uint_format(dereg_req_data, hf_dereg_req_reason_flag, tvb, offset, 1, reason_flag, "Reason: 0x%02x (%s)", reason_flag, wmem_strbuf_get_str(reasonflags_strbuf)); #if 0 /* XXX: ToDo?? Flags to be displayed under a subtree ? */ dereg_req_reason_flag_tree = proto_item_add_subtree(dereg_req_reason_flag, ett_dereg_req_reason_flag); #endif offset += 1; gmd_cnt = tvb_get_ntohs(tvb, offset); /* Group Mem Data Count */ proto_tree_add_item(dereg_req_data, hf_sasp_gmd_cnt, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; /*Group Mem Data */ for (i=0; i