13c602fabSXin LI /* Copyright (c) 2013, The TCPDUMP project 23c602fabSXin LI * All rights reserved. 33c602fabSXin LI * 43c602fabSXin LI * Redistribution and use in source and binary forms, with or without 53c602fabSXin LI * modification, are permitted provided that the following conditions are met: 63c602fabSXin LI * 73c602fabSXin LI * 1. Redistributions of source code must retain the above copyright notice, this 83c602fabSXin LI * list of conditions and the following disclaimer. 93c602fabSXin LI * 2. Redistributions in binary form must reproduce the above copyright notice, 103c602fabSXin LI * this list of conditions and the following disclaimer in the documentation 113c602fabSXin LI * and/or other materials provided with the distribution. 123c602fabSXin LI * 133c602fabSXin LI * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 143c602fabSXin LI * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 153c602fabSXin LI * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 163c602fabSXin LI * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 173c602fabSXin LI * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 183c602fabSXin LI * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 193c602fabSXin LI * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 203c602fabSXin LI * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 213c602fabSXin LI * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 223c602fabSXin LI * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 233c602fabSXin LI */ 243c602fabSXin LI 253340d773SGleb Smirnoff /* \summary: Message Transfer Part 3 (MTP3) User Adaptation Layer (M3UA) printer */ 263340d773SGleb Smirnoff 273340d773SGleb Smirnoff /* RFC 4666 */ 283340d773SGleb Smirnoff 293c602fabSXin LI #ifdef HAVE_CONFIG_H 30*ee67461eSJoseph Mingrone #include <config.h> 313c602fabSXin LI #endif 323c602fabSXin LI 33*ee67461eSJoseph Mingrone #include "netdissect-stdinc.h" 343c602fabSXin LI 35*ee67461eSJoseph Mingrone #define ND_LONGJMP_FROM_TCHECK 363340d773SGleb Smirnoff #include "netdissect.h" 373c602fabSXin LI #include "extract.h" 383c602fabSXin LI 393c602fabSXin LI 403c602fabSXin LI #define M3UA_REL_1_0 1 413c602fabSXin LI 423c602fabSXin LI struct m3ua_common_header { 43*ee67461eSJoseph Mingrone nd_uint8_t v; 44*ee67461eSJoseph Mingrone nd_uint8_t reserved; 45*ee67461eSJoseph Mingrone nd_uint8_t msg_class; 46*ee67461eSJoseph Mingrone nd_uint8_t msg_type; 47*ee67461eSJoseph Mingrone nd_uint32_t len; 483c602fabSXin LI }; 493c602fabSXin LI 503c602fabSXin LI struct m3ua_param_header { 51*ee67461eSJoseph Mingrone nd_uint16_t tag; 52*ee67461eSJoseph Mingrone nd_uint16_t len; 533c602fabSXin LI }; 543c602fabSXin LI 553c602fabSXin LI /* message classes */ 563c602fabSXin LI #define M3UA_MSGC_MGMT 0 573c602fabSXin LI #define M3UA_MSGC_TRANSFER 1 583c602fabSXin LI #define M3UA_MSGC_SSNM 2 593c602fabSXin LI #define M3UA_MSGC_ASPSM 3 603c602fabSXin LI #define M3UA_MSGC_ASPTM 4 613c602fabSXin LI /* reserved values */ 623c602fabSXin LI #define M3UA_MSGC_RKM 9 633c602fabSXin LI 643c602fabSXin LI static const struct tok MessageClasses[] = { 653c602fabSXin LI { M3UA_MSGC_MGMT, "Management" }, 663c602fabSXin LI { M3UA_MSGC_TRANSFER, "Transfer" }, 673c602fabSXin LI { M3UA_MSGC_SSNM, "SS7" }, 683c602fabSXin LI { M3UA_MSGC_ASPSM, "ASP" }, 693c602fabSXin LI { M3UA_MSGC_ASPTM, "ASP" }, 700bff6a5aSEd Maste { M3UA_MSGC_RKM, "Routing Key Management"}, 713c602fabSXin LI { 0, NULL } 723c602fabSXin LI }; 733c602fabSXin LI 743c602fabSXin LI /* management messages */ 753c602fabSXin LI #define M3UA_MGMT_ERROR 0 763c602fabSXin LI #define M3UA_MGMT_NOTIFY 1 773c602fabSXin LI 783c602fabSXin LI static const struct tok MgmtMessages[] = { 793c602fabSXin LI { M3UA_MGMT_ERROR, "Error" }, 803c602fabSXin LI { M3UA_MGMT_NOTIFY, "Notify" }, 813c602fabSXin LI { 0, NULL } 823c602fabSXin LI }; 833c602fabSXin LI 843c602fabSXin LI /* transfer messages */ 853c602fabSXin LI #define M3UA_TRANSFER_DATA 1 863c602fabSXin LI 873c602fabSXin LI static const struct tok TransferMessages[] = { 883c602fabSXin LI { M3UA_TRANSFER_DATA, "Data" }, 893c602fabSXin LI { 0, NULL } 903c602fabSXin LI }; 913c602fabSXin LI 923c602fabSXin LI /* SS7 Signaling Network Management messages */ 933c602fabSXin LI #define M3UA_SSNM_DUNA 1 943c602fabSXin LI #define M3UA_SSNM_DAVA 2 953c602fabSXin LI #define M3UA_SSNM_DAUD 3 963c602fabSXin LI #define M3UA_SSNM_SCON 4 973c602fabSXin LI #define M3UA_SSNM_DUPU 5 983c602fabSXin LI #define M3UA_SSNM_DRST 6 993c602fabSXin LI 1003c602fabSXin LI static const struct tok SS7Messages[] = { 1013c602fabSXin LI { M3UA_SSNM_DUNA, "Destination Unavailable" }, 1023c602fabSXin LI { M3UA_SSNM_DAVA, "Destination Available" }, 1033c602fabSXin LI { M3UA_SSNM_DAUD, "Destination State Audit" }, 1043c602fabSXin LI { M3UA_SSNM_SCON, "Signalling Congestion" }, 1053c602fabSXin LI { M3UA_SSNM_DUPU, "Destination User Part Unavailable" }, 1063c602fabSXin LI { M3UA_SSNM_DRST, "Destination Restricted" }, 1073c602fabSXin LI { 0, NULL } 1083c602fabSXin LI }; 1093c602fabSXin LI 1103c602fabSXin LI /* ASP State Maintenance messages */ 1113c602fabSXin LI #define M3UA_ASP_UP 1 1123c602fabSXin LI #define M3UA_ASP_DN 2 1133c602fabSXin LI #define M3UA_ASP_BEAT 3 1143c602fabSXin LI #define M3UA_ASP_UP_ACK 4 1153c602fabSXin LI #define M3UA_ASP_DN_ACK 5 1163c602fabSXin LI #define M3UA_ASP_BEAT_ACK 6 1173c602fabSXin LI 1183c602fabSXin LI static const struct tok ASPStateMessages[] = { 1193c602fabSXin LI { M3UA_ASP_UP, "Up" }, 1203c602fabSXin LI { M3UA_ASP_DN, "Down" }, 1213c602fabSXin LI { M3UA_ASP_BEAT, "Heartbeat" }, 1223c602fabSXin LI { M3UA_ASP_UP_ACK, "Up Acknowledgement" }, 1233c602fabSXin LI { M3UA_ASP_DN_ACK, "Down Acknowledgement" }, 1243c602fabSXin LI { M3UA_ASP_BEAT_ACK, "Heartbeat Acknowledgement" }, 1253c602fabSXin LI { 0, NULL } 1263c602fabSXin LI }; 1273c602fabSXin LI 1283c602fabSXin LI /* ASP Traffic Maintenance messages */ 1293c602fabSXin LI #define M3UA_ASP_AC 1 1303c602fabSXin LI #define M3UA_ASP_IA 2 1313c602fabSXin LI #define M3UA_ASP_AC_ACK 3 1323c602fabSXin LI #define M3UA_ASP_IA_ACK 4 1333c602fabSXin LI 1343c602fabSXin LI static const struct tok ASPTrafficMessages[] = { 1353c602fabSXin LI { M3UA_ASP_AC, "Active" }, 1363c602fabSXin LI { M3UA_ASP_IA, "Inactive" }, 1373c602fabSXin LI { M3UA_ASP_AC_ACK, "Active Acknowledgement" }, 1383c602fabSXin LI { M3UA_ASP_IA_ACK, "Inactive Acknowledgement" }, 1393c602fabSXin LI { 0, NULL } 1403c602fabSXin LI }; 1413c602fabSXin LI 1423c602fabSXin LI /* Routing Key Management messages */ 1433c602fabSXin LI #define M3UA_RKM_REQ 1 1443c602fabSXin LI #define M3UA_RKM_RSP 2 1453c602fabSXin LI #define M3UA_RKM_DEREQ 3 1463c602fabSXin LI #define M3UA_RKM_DERSP 4 1473c602fabSXin LI 1483c602fabSXin LI static const struct tok RoutingKeyMgmtMessages[] = { 1493c602fabSXin LI { M3UA_RKM_REQ, "Registration Request" }, 1503c602fabSXin LI { M3UA_RKM_RSP, "Registration Response" }, 1513c602fabSXin LI { M3UA_RKM_DEREQ, "Deregistration Request" }, 1523c602fabSXin LI { M3UA_RKM_DERSP, "Deregistration Response" }, 1533c602fabSXin LI { 0, NULL } 1543c602fabSXin LI }; 1553c602fabSXin LI 156*ee67461eSJoseph Mingrone static const struct uint_tokary m3ua_msgc2tokary[] = { 157*ee67461eSJoseph Mingrone { M3UA_MSGC_MGMT, MgmtMessages }, 158*ee67461eSJoseph Mingrone { M3UA_MSGC_TRANSFER, TransferMessages }, 159*ee67461eSJoseph Mingrone { M3UA_MSGC_SSNM, SS7Messages }, 160*ee67461eSJoseph Mingrone { M3UA_MSGC_ASPSM, ASPStateMessages }, 161*ee67461eSJoseph Mingrone { M3UA_MSGC_ASPTM, ASPTrafficMessages }, 162*ee67461eSJoseph Mingrone { M3UA_MSGC_RKM, RoutingKeyMgmtMessages }, 163*ee67461eSJoseph Mingrone /* uint2tokary() does not use array termination. */ 164*ee67461eSJoseph Mingrone }; 165*ee67461eSJoseph Mingrone 1663c602fabSXin LI /* M3UA Parameters */ 1673c602fabSXin LI #define M3UA_PARAM_INFO 0x0004 1683c602fabSXin LI #define M3UA_PARAM_ROUTING_CTX 0x0006 1693c602fabSXin LI #define M3UA_PARAM_DIAGNOSTIC 0x0007 1703c602fabSXin LI #define M3UA_PARAM_HB_DATA 0x0009 1713c602fabSXin LI #define M3UA_PARAM_TRAFFIC_MODE_TYPE 0x000b 1723c602fabSXin LI #define M3UA_PARAM_ERROR_CODE 0x000c 1733c602fabSXin LI #define M3UA_PARAM_STATUS 0x000d 1743c602fabSXin LI #define M3UA_PARAM_ASP_ID 0x0011 1753c602fabSXin LI #define M3UA_PARAM_AFFECTED_POINT_CODE 0x0012 1763c602fabSXin LI #define M3UA_PARAM_CORR_ID 0x0013 1773c602fabSXin LI 1783c602fabSXin LI #define M3UA_PARAM_NETWORK_APPEARANCE 0x0200 1793c602fabSXin LI #define M3UA_PARAM_USER 0x0204 1803c602fabSXin LI #define M3UA_PARAM_CONGESTION_INDICATION 0x0205 1813c602fabSXin LI #define M3UA_PARAM_CONCERNED_DST 0x0206 1823c602fabSXin LI #define M3UA_PARAM_ROUTING_KEY 0x0207 1833c602fabSXin LI #define M3UA_PARAM_REG_RESULT 0x0208 1843c602fabSXin LI #define M3UA_PARAM_DEREG_RESULT 0x0209 1853c602fabSXin LI #define M3UA_PARAM_LOCAL_ROUTING_KEY_ID 0x020a 1863c602fabSXin LI #define M3UA_PARAM_DST_POINT_CODE 0x020b 1873c602fabSXin LI #define M3UA_PARAM_SI 0x020c 1883c602fabSXin LI #define M3UA_PARAM_ORIGIN_POINT_CODE_LIST 0x020e 1893c602fabSXin LI #define M3UA_PARAM_PROTO_DATA 0x0210 1903c602fabSXin LI #define M3UA_PARAM_REG_STATUS 0x0212 1913c602fabSXin LI #define M3UA_PARAM_DEREG_STATUS 0x0213 1923c602fabSXin LI 1933c602fabSXin LI static const struct tok ParamName[] = { 1943c602fabSXin LI { M3UA_PARAM_INFO, "INFO String" }, 1953c602fabSXin LI { M3UA_PARAM_ROUTING_CTX, "Routing Context" }, 1963c602fabSXin LI { M3UA_PARAM_DIAGNOSTIC, "Diagnostic Info" }, 1973c602fabSXin LI { M3UA_PARAM_HB_DATA, "Heartbeat Data" }, 1983c602fabSXin LI { M3UA_PARAM_TRAFFIC_MODE_TYPE, "Traffic Mode Type" }, 1993c602fabSXin LI { M3UA_PARAM_ERROR_CODE, "Error Code" }, 2003c602fabSXin LI { M3UA_PARAM_STATUS, "Status" }, 2013c602fabSXin LI { M3UA_PARAM_ASP_ID, "ASP Identifier" }, 2023c602fabSXin LI { M3UA_PARAM_AFFECTED_POINT_CODE, "Affected Point Code" }, 2033c602fabSXin LI { M3UA_PARAM_CORR_ID, "Correlation ID" }, 2043c602fabSXin LI { M3UA_PARAM_NETWORK_APPEARANCE, "Network Appearance" }, 2053c602fabSXin LI { M3UA_PARAM_USER, "User/Cause" }, 2063c602fabSXin LI { M3UA_PARAM_CONGESTION_INDICATION, "Congestion Indications" }, 2073c602fabSXin LI { M3UA_PARAM_CONCERNED_DST, "Concerned Destination" }, 2083c602fabSXin LI { M3UA_PARAM_ROUTING_KEY, "Routing Key" }, 2093c602fabSXin LI { M3UA_PARAM_REG_RESULT, "Registration Result" }, 2103c602fabSXin LI { M3UA_PARAM_DEREG_RESULT, "Deregistration Result" }, 2113c602fabSXin LI { M3UA_PARAM_LOCAL_ROUTING_KEY_ID, "Local Routing Key Identifier" }, 2123c602fabSXin LI { M3UA_PARAM_DST_POINT_CODE, "Destination Point Code" }, 2133c602fabSXin LI { M3UA_PARAM_SI, "Service Indicators" }, 2143c602fabSXin LI { M3UA_PARAM_ORIGIN_POINT_CODE_LIST, "Originating Point Code List" }, 2153c602fabSXin LI { M3UA_PARAM_PROTO_DATA, "Protocol Data" }, 2163c602fabSXin LI { M3UA_PARAM_REG_STATUS, "Registration Status" }, 2173c602fabSXin LI { M3UA_PARAM_DEREG_STATUS, "Deregistration Status" }, 2183c602fabSXin LI { 0, NULL } 2193c602fabSXin LI }; 2203c602fabSXin LI 2213c602fabSXin LI static void 2223c602fabSXin LI tag_value_print(netdissect_options *ndo, 2233c602fabSXin LI const u_char *buf, const uint16_t tag, const uint16_t size) 2243c602fabSXin LI { 2253c602fabSXin LI switch (tag) { 2263c602fabSXin LI case M3UA_PARAM_NETWORK_APPEARANCE: 2273c602fabSXin LI case M3UA_PARAM_ROUTING_CTX: 2283c602fabSXin LI case M3UA_PARAM_CORR_ID: 2293c602fabSXin LI /* buf and size don't include the header */ 2303c602fabSXin LI if (size < 4) 2313340d773SGleb Smirnoff goto invalid; 232*ee67461eSJoseph Mingrone ND_PRINT("0x%08x", GET_BE_U_4(buf)); 2333c602fabSXin LI break; 2343c602fabSXin LI /* ... */ 2353c602fabSXin LI default: 236*ee67461eSJoseph Mingrone ND_PRINT("(length %zu)", size + sizeof(struct m3ua_param_header)); 2373c602fabSXin LI } 238*ee67461eSJoseph Mingrone ND_TCHECK_LEN(buf, size); 2393c602fabSXin LI return; 2403c602fabSXin LI 2413340d773SGleb Smirnoff invalid: 242*ee67461eSJoseph Mingrone nd_print_invalid(ndo); 243*ee67461eSJoseph Mingrone ND_TCHECK_LEN(buf, size); 2443c602fabSXin LI } 2453c602fabSXin LI 2463c602fabSXin LI /* 2473c602fabSXin LI * 0 1 2 3 2483c602fabSXin LI * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2493c602fabSXin LI * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 2503c602fabSXin LI * | Parameter Tag | Parameter Length | 2513c602fabSXin LI * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 2523c602fabSXin LI * \ \ 2533c602fabSXin LI * / Parameter Value / 2543c602fabSXin LI * \ \ 2553c602fabSXin LI * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 2563c602fabSXin LI */ 2573c602fabSXin LI static void 2583c602fabSXin LI m3ua_tags_print(netdissect_options *ndo, 2593c602fabSXin LI const u_char *buf, const u_int size) 2603c602fabSXin LI { 2613c602fabSXin LI const u_char *p = buf; 2623c602fabSXin LI int align; 2633c602fabSXin LI uint16_t hdr_tag; 2643c602fabSXin LI uint16_t hdr_len; 2653c602fabSXin LI 2663c602fabSXin LI while (p < buf + size) { 2673c602fabSXin LI if (p + sizeof(struct m3ua_param_header) > buf + size) 2683340d773SGleb Smirnoff goto invalid; 2693c602fabSXin LI /* Parameter Tag */ 270*ee67461eSJoseph Mingrone hdr_tag = GET_BE_U_2(p); 271*ee67461eSJoseph Mingrone ND_PRINT("\n\t\t\t%s: ", tok2str(ParamName, "Unknown Parameter (0x%04x)", hdr_tag)); 2723c602fabSXin LI /* Parameter Length */ 273*ee67461eSJoseph Mingrone hdr_len = GET_BE_U_2(p + 2); 2743c602fabSXin LI if (hdr_len < sizeof(struct m3ua_param_header)) 2753340d773SGleb Smirnoff goto invalid; 2763c602fabSXin LI /* Parameter Value */ 2773c602fabSXin LI align = (p + hdr_len - buf) % 4; 2783c602fabSXin LI align = align ? 4 - align : 0; 279*ee67461eSJoseph Mingrone ND_TCHECK_LEN(p, hdr_len + align); 2803c602fabSXin LI tag_value_print(ndo, p, hdr_tag, hdr_len - sizeof(struct m3ua_param_header)); 2813c602fabSXin LI p += hdr_len + align; 2823c602fabSXin LI } 2833c602fabSXin LI return; 2843c602fabSXin LI 2853340d773SGleb Smirnoff invalid: 286*ee67461eSJoseph Mingrone nd_print_invalid(ndo); 287*ee67461eSJoseph Mingrone ND_TCHECK_LEN(buf, size); 2883c602fabSXin LI } 2893c602fabSXin LI 2903c602fabSXin LI /* 2913c602fabSXin LI * 0 1 2 3 2923c602fabSXin LI * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2933c602fabSXin LI * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 2943c602fabSXin LI * | Version | Reserved | Message Class | Message Type | 2953c602fabSXin LI * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 2963c602fabSXin LI * | Message Length | 2973c602fabSXin LI * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 2983c602fabSXin LI * \ \ 2993c602fabSXin LI * / / 3003c602fabSXin LI */ 3013c602fabSXin LI void 3023c602fabSXin LI m3ua_print(netdissect_options *ndo, 3033c602fabSXin LI const u_char *buf, const u_int size) 3043c602fabSXin LI { 3053c602fabSXin LI const struct m3ua_common_header *hdr = (const struct m3ua_common_header *) buf; 3063c602fabSXin LI const struct tok *dict; 307*ee67461eSJoseph Mingrone uint8_t msg_class; 3083c602fabSXin LI 309*ee67461eSJoseph Mingrone ndo->ndo_protocol = "m3ua"; 3103c602fabSXin LI /* size includes the header */ 3113c602fabSXin LI if (size < sizeof(struct m3ua_common_header)) 3123340d773SGleb Smirnoff goto invalid; 313*ee67461eSJoseph Mingrone ND_TCHECK_SIZE(hdr); 314*ee67461eSJoseph Mingrone if (GET_U_1(hdr->v) != M3UA_REL_1_0) 3153c602fabSXin LI return; 3163c602fabSXin LI 317*ee67461eSJoseph Mingrone msg_class = GET_U_1(hdr->msg_class); 318*ee67461eSJoseph Mingrone dict = uint2tokary(m3ua_msgc2tokary, msg_class); 3193c602fabSXin LI 320*ee67461eSJoseph Mingrone ND_PRINT("\n\t\t%s", tok2str(MessageClasses, "Unknown message class %i", msg_class)); 3213c602fabSXin LI if (dict != NULL) 322*ee67461eSJoseph Mingrone ND_PRINT(" %s Message", 323*ee67461eSJoseph Mingrone tok2str(dict, "Unknown (0x%02x)", GET_U_1(hdr->msg_type))); 3243c602fabSXin LI 325*ee67461eSJoseph Mingrone if (size != GET_BE_U_4(hdr->len)) 326*ee67461eSJoseph Mingrone ND_PRINT("\n\t\t\t@@@@@@ Corrupted length %u of message @@@@@@", 327*ee67461eSJoseph Mingrone GET_BE_U_4(hdr->len)); 3283c602fabSXin LI else 329*ee67461eSJoseph Mingrone m3ua_tags_print(ndo, buf + sizeof(struct m3ua_common_header), 330*ee67461eSJoseph Mingrone GET_BE_U_4(hdr->len) - sizeof(struct m3ua_common_header)); 3313c602fabSXin LI return; 3323c602fabSXin LI 3333340d773SGleb Smirnoff invalid: 334*ee67461eSJoseph Mingrone nd_print_invalid(ndo); 335*ee67461eSJoseph Mingrone ND_TCHECK_LEN(buf, size); 3363c602fabSXin LI } 3373c602fabSXin LI 338