forked from osmocom/wireshark
Francesco Fondelli:
Protocol Extensions for Support of Diffserv-aware MPLS Traffic Engineering (DSTE) as per RFC 4124. svn path=/trunk/; revision=18727
This commit is contained in:
parent
4070ac6967
commit
917bdbc877
1
AUTHORS
1
AUTHORS
|
@ -2273,6 +2273,7 @@ Francesco Fondelli <francesco.fondelli [AT] gmail.com> {
|
|||
ICE protocol support
|
||||
DCCP protocol support
|
||||
MPLS OAM support, Y.1711
|
||||
RSVP/OSPF Extensions for Support of Diffserv-aware MPLS-TE, RFC 4124
|
||||
}
|
||||
|
||||
Bill Meier <wmeier [AT] newsguy.com> {
|
||||
|
|
|
@ -19,7 +19,11 @@
|
|||
*
|
||||
* Added support to E-NNI routing (OIF2003.259.02)
|
||||
* - (c) 2004 Roberto Morro <roberto.morro[AT]tilab.com>
|
||||
|
||||
*
|
||||
* Added support of MPLS Diffserv-aware TE (RFC 4124); new BC sub-TLV
|
||||
* - (c) 2006 (FF) <francesco.fondelli[AT]gmail.com>
|
||||
*
|
||||
*
|
||||
* TOS - support is not fully implemented
|
||||
*
|
||||
* Wireshark - Network traffic analyzer
|
||||
|
@ -425,6 +429,7 @@ enum {
|
|||
OSPFF_LS_MPLS_LOCAL_IFID,
|
||||
OSPFF_LS_MPLS_REMOTE_IFID,
|
||||
OSPFF_LS_MPLS_LINKCOLOR,
|
||||
OSPFF_LS_MPLS_BC_MODEL_ID,
|
||||
|
||||
OSPFF_V2_OPTIONS,
|
||||
OSPFF_V2_OPTIONS_E,
|
||||
|
@ -578,6 +583,9 @@ static hf_register_info ospff_info[] = {
|
|||
{&ospf_filter[OSPFF_LS_MPLS_LINKCOLOR],
|
||||
{ "MPLS/TE Link Resource Class/Color", "ospf.mpls.linkcolor", FT_UINT32,
|
||||
BASE_HEX, NULL, 0x0, "MPLS/TE Link Resource Class/Color", HFILL }},
|
||||
{&ospf_filter[OSPFF_LS_MPLS_BC_MODEL_ID],
|
||||
{ "MPLS/DSTE Bandwidth Constraints Model Id", "ospf.mpls.bc", FT_UINT8,
|
||||
BASE_HEX, NULL, 0x0, "MPLS/DSTE Bandwidth Constraints Model Id", HFILL }},
|
||||
|
||||
{&ospf_filter[OSPFF_V2_OPTIONS],
|
||||
{ "Options", "ospf.v2.options", FT_UINT8, BASE_HEX,
|
||||
|
@ -1476,7 +1484,7 @@ is_opaque(int lsa_type)
|
|||
|
||||
/* MPLS/TE Link STLV types */
|
||||
enum {
|
||||
MPLS_LINK_TYPE = 1,
|
||||
MPLS_LINK_TYPE = 1, /* RFC 3630, OSPF-TE */
|
||||
MPLS_LINK_ID,
|
||||
MPLS_LINK_LOCAL_IF,
|
||||
MPLS_LINK_REMOTE_IF,
|
||||
|
@ -1485,10 +1493,11 @@ enum {
|
|||
MPLS_LINK_MAX_RES_BW,
|
||||
MPLS_LINK_UNRES_BW,
|
||||
MPLS_LINK_COLOR,
|
||||
MPLS_LINK_LOCAL_REMOTE_ID = 11,
|
||||
MPLS_LINK_LOCAL_REMOTE_ID = 11, /* RFC 4203, GMPLS */
|
||||
MPLS_LINK_PROTECTION = 14,
|
||||
MPLS_LINK_IF_SWITCHING_DESC,
|
||||
MPLS_LINK_SHARED_RISK_GROUP
|
||||
MPLS_LINK_SHARED_RISK_GROUP,
|
||||
MPLS_LINK_BANDWIDTH_CONSTRAINT = 17 /* RFC 4124, OSPF-DSTE */
|
||||
};
|
||||
|
||||
/* OIF TLV types */
|
||||
|
@ -1516,6 +1525,7 @@ static const value_string mpls_link_stlv_str[] = {
|
|||
{MPLS_LINK_PROTECTION, "Link Protection Type"},
|
||||
{MPLS_LINK_IF_SWITCHING_DESC, "Interface Switching Capability Descriptor"},
|
||||
{MPLS_LINK_SHARED_RISK_GROUP, "Shared Risk Link Group"},
|
||||
{MPLS_LINK_BANDWIDTH_CONSTRAINT, "Bandwidth Constraints"},
|
||||
{OIF_LOCAL_NODE_ID, "Local Node ID"},
|
||||
{OIF_REMOTE_NODE_ID, "Remote Node ID"},
|
||||
{OIF_SONET_SDH_SWITCHING_CAPABILITY, "Sonet/SDH Interface Switching Capability"},
|
||||
|
@ -1553,6 +1563,9 @@ dissect_ospf_lsa_mpls(tvbuff_t *tvb, int offset, proto_tree *tree,
|
|||
int i;
|
||||
guint8 switch_cap;
|
||||
|
||||
const guint8 allzero[] = { 0x00, 0x00, 0x00 };
|
||||
guint num_bcs = 0;
|
||||
|
||||
ti = proto_tree_add_text(tree, tvb, offset, length,
|
||||
"MPLS Traffic Engineering LSA");
|
||||
proto_tree_add_item_hidden(tree, ospf_filter[OSPFF_LS_MPLS],
|
||||
|
@ -1705,12 +1718,79 @@ dissect_ospf_lsa_mpls(tvbuff_t *tvb, int offset, proto_tree *tree,
|
|||
stlv_len);
|
||||
for (i = 0; i < 8; i++) {
|
||||
proto_tree_add_text(stlv_tree, tvb, stlv_offset+4+(i*4), 4,
|
||||
"Pri %d: %.10g bytes/s (%.0f bits/s)", i,
|
||||
"Pri (or TE-Class) %d: %.10g bytes/s (%.0f bits/s)", i,
|
||||
tvb_get_ntohieee_float(tvb, stlv_offset + 4 + i*4),
|
||||
tvb_get_ntohieee_float(tvb, stlv_offset + 4 + i*4) * 8.0);
|
||||
}
|
||||
break;
|
||||
|
||||
case MPLS_LINK_BANDWIDTH_CONSTRAINT:
|
||||
/*
|
||||
The "Bandwidth Constraints" sub-TLV format is illustrated below:
|
||||
|
||||
0 1 2 3
|
||||
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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| BC Model Id | Reserved |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| BC0 value |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// . . . //
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| BCh value |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
|
||||
ti = proto_tree_add_text(tlv_tree, tvb, stlv_offset, stlv_len+4,
|
||||
"%s", stlv_name);
|
||||
|
||||
stlv_tree = proto_item_add_subtree(ti, ett_ospf_lsa_mpls_link_stlv);
|
||||
|
||||
proto_tree_add_text(stlv_tree, tvb, stlv_offset, 2,
|
||||
"TLV Type: %u: %s", stlv_type, stlv_name);
|
||||
|
||||
proto_tree_add_text(stlv_tree, tvb, stlv_offset+2, 2, "TLV Length: %u",
|
||||
stlv_len);
|
||||
|
||||
proto_tree_add_item(stlv_tree,
|
||||
ospf_filter[OSPFF_LS_MPLS_BC_MODEL_ID],
|
||||
tvb, stlv_offset+4, 1, FALSE);
|
||||
|
||||
/* 3 octets reserved +5, +6 and +7 (all 0x00) */
|
||||
if(tvb_memeql(tvb, stlv_offset+5, allzero, 3) == -1) {
|
||||
proto_tree_add_text(stlv_tree, tvb, stlv_offset+5, 3,
|
||||
"Warning: these bytes are reserved and must be 0x00");
|
||||
}
|
||||
|
||||
if(((stlv_len % 4)!=0)) {
|
||||
proto_tree_add_text(stlv_tree, tvb, stlv_offset+4, stlv_len,
|
||||
"Malformed Packet: Lenght must be N x 4 octets");
|
||||
break;
|
||||
}
|
||||
|
||||
/* stlv_len shound range from 4 to 36 bytes */
|
||||
num_bcs = (stlv_len - 4)/4;
|
||||
|
||||
if(num_bcs>8) {
|
||||
proto_tree_add_text(stlv_tree, tvb, stlv_offset+4, stlv_len,
|
||||
"Malformed Packet: too many BC (%u)", num_bcs);
|
||||
break;
|
||||
}
|
||||
|
||||
if(num_bcs==0) {
|
||||
proto_tree_add_text(stlv_tree, tvb, stlv_offset+4, stlv_len,
|
||||
"Malformed Packet: Bandwidth Constraints sub-TLV with no BC?");
|
||||
break;
|
||||
}
|
||||
|
||||
for(i = 0; i < num_bcs; i++) {
|
||||
proto_tree_add_text(stlv_tree, tvb, stlv_offset+8+(i*4), 4,
|
||||
"BC %d: %.10g bytes/s (%.0f bits/s)", i,
|
||||
tvb_get_ntohieee_float(tvb, stlv_offset + 8 + i*4),
|
||||
tvb_get_ntohieee_float(tvb, stlv_offset + 8 + i*4) * 8.0);
|
||||
}
|
||||
break;
|
||||
|
||||
case MPLS_LINK_LOCAL_REMOTE_ID:
|
||||
ti = proto_tree_add_text(tlv_tree, tvb, stlv_offset, stlv_len+4,
|
||||
"%s: %d (0x%x) - %d (0x%x)", stlv_name,
|
||||
|
|
|
@ -55,6 +55,9 @@
|
|||
*
|
||||
* August 22, 2005: added support for tapping and conversations.
|
||||
* (Manu Pathak) <mapathak[AT]cisco.com>
|
||||
*
|
||||
* July 4, 2006: added support for RFC4124; new CLASSTYPE object dissector
|
||||
* (FF) <francesco.fondelli[AT]gmail.com>
|
||||
*/
|
||||
|
||||
|
||||
|
@ -240,6 +243,7 @@ enum {
|
|||
TT_DIFFSERV,
|
||||
TT_DIFFSERV_MAP,
|
||||
TT_DIFFSERV_MAP_PHBID,
|
||||
TT_CLASSTYPE,
|
||||
TT_UNKNOWN_CLASS,
|
||||
|
||||
TT_MAX
|
||||
|
@ -343,6 +347,8 @@ enum rsvp_classes {
|
|||
|
||||
RSVP_CLASS_DIFFSERV = 65,
|
||||
|
||||
RSVP_CLASS_CLASSTYPE = 66, /* FF: RFC4124 */
|
||||
|
||||
RSVP_CLASS_SUGGESTED_LABEL = 129,
|
||||
RSVP_CLASS_ACCEPTABLE_LABEL_SET,
|
||||
RSVP_CLASS_RESTART_CAP,
|
||||
|
@ -390,6 +396,7 @@ static value_string rsvp_class_vals[] = {
|
|||
{RSVP_CLASS_LABEL_SET, "LABEL-SET object"},
|
||||
{RSVP_CLASS_PROTECTION, "PROTECTION object"},
|
||||
{RSVP_CLASS_DIFFSERV, "DIFFSERV object"},
|
||||
{RSVP_CLASS_CLASSTYPE, "CLASSTYPE object"},
|
||||
{RSVP_CLASS_SUGGESTED_LABEL, "SUGGESTED-LABEL object"},
|
||||
{RSVP_CLASS_ACCEPTABLE_LABEL_SET, "ACCEPTABLE-LABEL-SET object"},
|
||||
{RSVP_CLASS_RESTART_CAP, "RESTART-CAPABILITY object"},
|
||||
|
@ -426,7 +433,8 @@ enum rsvp_error_types {
|
|||
RSVP_ERROR_SYSTEM,
|
||||
RSVP_ERROR_ROUTING,
|
||||
RSVP_ERROR_NOTIFY,
|
||||
RSVP_ERROR_DIFFSERV = 27
|
||||
RSVP_ERROR_DIFFSERV = 27,
|
||||
RSVP_ERROR_DSTE = 28 /* FF: RFC4124 */
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -470,6 +478,18 @@ enum {
|
|||
RSVP_DIFFSERV_ERROR_PERLSP_CONTEXT_ALLOC_FAIL
|
||||
};
|
||||
|
||||
/* FF: RFC4124 */
|
||||
enum {
|
||||
RSVP_DSTE_ERROR_UNEXPECTED_CLASSTYPEOBJ = 1,
|
||||
RSVP_DSTE_ERROR_UNSUPPORTED_CLASSTYPE,
|
||||
RSVP_DSTE_ERROR_INVALID_CLASSTYPE_VALUE,
|
||||
RSVP_DSTE_ERROR_CT_SETUP_PRIO_NOT_CONFIGURED,
|
||||
RSVP_DSTE_ERROR_CT_HOLDING_PRIO_NOT_CONFIGURED,
|
||||
RSVP_DSTE_ERROR_CT_SETUP_PRIO_AND_CT_HOLDING_PRIO_NOT_CONFIGURED,
|
||||
RSVP_DSTE_ERROR_INCONSISTENCY_PSC_CT,
|
||||
RSVP_DSTE_ERROR_INCONSISTENCY_PHB_CT
|
||||
};
|
||||
|
||||
static value_string rsvp_error_codes[] = {
|
||||
{RSVP_ERROR_CONFIRM, "Confirmation"},
|
||||
{RSVP_ERROR_ADMISSION, "Admission Control Failure "},
|
||||
|
@ -489,6 +509,7 @@ static value_string rsvp_error_codes[] = {
|
|||
{RSVP_ERROR_ROUTING, "Routing Error"},
|
||||
{RSVP_ERROR_NOTIFY, "RSVP Notify Error"},
|
||||
{RSVP_ERROR_DIFFSERV, "RSVP Diff-Serv Error"},
|
||||
{RSVP_ERROR_DSTE, "RSVP DiffServ-aware TE Error"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
|
@ -538,6 +559,20 @@ static value_string rsvp_diffserv_error_vals[] = {
|
|||
{0, NULL}
|
||||
};
|
||||
|
||||
/* FF: RFC4124 */
|
||||
static value_string rsvp_diffserv_aware_te_error_vals[] = {
|
||||
{RSVP_DSTE_ERROR_UNEXPECTED_CLASSTYPEOBJ, "Unexpected CLASSTYPE object"},
|
||||
{RSVP_DSTE_ERROR_UNSUPPORTED_CLASSTYPE, "Unsupported Class-Type"},
|
||||
{RSVP_DSTE_ERROR_INVALID_CLASSTYPE_VALUE, "Invalid Class-Type value"},
|
||||
{RSVP_DSTE_ERROR_CT_SETUP_PRIO_NOT_CONFIGURED, "CT and setup priority do not form a configured TE-Class"},
|
||||
{RSVP_DSTE_ERROR_CT_HOLDING_PRIO_NOT_CONFIGURED, "CT and holding priority do not form a configured TE-Class"},
|
||||
{RSVP_DSTE_ERROR_CT_SETUP_PRIO_AND_CT_HOLDING_PRIO_NOT_CONFIGURED,
|
||||
"CT and setup priority do not form a configured TE-Class AND CT and holding priority do not form a configured TE-Class"},
|
||||
{RSVP_DSTE_ERROR_INCONSISTENCY_PSC_CT, "Inconsistency between signaled PSC and signaled CT"},
|
||||
{RSVP_DSTE_ERROR_INCONSISTENCY_PHB_CT, "Inconsistency between signaled PHBs and signaled CT"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
/*
|
||||
* Defines the reservation style plus style-specific information that
|
||||
* is not a FLOWSPEC or FILTER_SPEC object, in a RESV message.
|
||||
|
@ -835,6 +870,7 @@ enum rsvp_filter_keys {
|
|||
RSVPF_LABEL_SET,
|
||||
RSVPF_PROTECTION,
|
||||
RSVPF_DIFFSERV,
|
||||
RSVPF_DSTE,
|
||||
|
||||
RSVPF_SUGGESTED_LABEL,
|
||||
RSVPF_ACCEPTABLE_LABEL_SET,
|
||||
|
@ -872,6 +908,9 @@ enum rsvp_filter_keys {
|
|||
RSVPF_DIFFSERV_PHBID_BIT14,
|
||||
RSVPF_DIFFSERV_PHBID_BIT15,
|
||||
|
||||
/* Diffserv-aware TE object */
|
||||
RSVPF_DSTE_CLASSTYPE,
|
||||
|
||||
/* Sentinel */
|
||||
RSVPF_MAX
|
||||
};
|
||||
|
@ -1032,6 +1071,10 @@ static hf_register_info rsvpf_info[] = {
|
|||
{ "DIFFSERV", "rsvp.diffserv", FT_NONE, BASE_NONE, NULL, 0x0,
|
||||
"", HFILL }},
|
||||
|
||||
{&rsvp_filter[RSVPF_DSTE],
|
||||
{ "CLASSTYPE", "rsvp.dste", FT_NONE, BASE_NONE, NULL, 0x0,
|
||||
"", HFILL }},
|
||||
|
||||
{&rsvp_filter[RSVPF_RESTART_CAP],
|
||||
{ "RESTART CAPABILITY", "rsvp.restart", FT_NONE, BASE_NONE, NULL, 0x0,
|
||||
"", HFILL }},
|
||||
|
@ -1161,8 +1204,12 @@ static hf_register_info rsvpf_info[] = {
|
|||
|
||||
{&rsvp_filter[RSVPF_DIFFSERV_PHBID_BIT15],
|
||||
{ PHBID_BIT15_DESCRIPTION, "rsvp.diffserv.phbid.bit15", FT_UINT16,
|
||||
BASE_DEC, VALS(phbid_bit15_vals), PHBID_BIT15_MASK, "Bit 15", HFILL }}
|
||||
BASE_DEC, VALS(phbid_bit15_vals), PHBID_BIT15_MASK, "Bit 15", HFILL }},
|
||||
|
||||
/* Diffserv-aware TE object field */
|
||||
{&rsvp_filter[RSVPF_DSTE_CLASSTYPE],
|
||||
{ "CT", "rsvp.dste.classtype", FT_UINT8, BASE_DEC, NULL, 0x0,
|
||||
NULL, HFILL }}
|
||||
};
|
||||
|
||||
/* RSVP Conversation related Hash functions */
|
||||
|
@ -1337,6 +1384,9 @@ static inline int rsvp_class_to_filter_num(int classnum)
|
|||
case RSVP_CLASS_DIFFSERV :
|
||||
return RSVPF_DIFFSERV;
|
||||
|
||||
case RSVP_CLASS_CLASSTYPE :
|
||||
return RSVPF_DSTE;
|
||||
|
||||
case RSVP_CLASS_NOTIFY_REQUEST :
|
||||
return RSVPF_NOTIFY_REQUEST;
|
||||
case RSVP_CLASS_ADMIN_STATUS :
|
||||
|
@ -1421,6 +1471,8 @@ static inline int rsvp_class_to_tree_type(int classnum)
|
|||
return TT_RESTART_CAP;
|
||||
case RSVP_CLASS_DIFFSERV :
|
||||
return TT_DIFFSERV;
|
||||
case RSVP_CLASS_CLASSTYPE:
|
||||
return TT_CLASSTYPE;
|
||||
case RSVP_CLASS_NOTIFY_REQUEST :
|
||||
return TT_UNKNOWN_CLASS;
|
||||
case RSVP_CLASS_ADMIN_STATUS :
|
||||
|
@ -1916,6 +1968,10 @@ dissect_rsvp_error_value (proto_tree *ti, tvbuff_t *tvb,
|
|||
break;
|
||||
case RSVP_ERROR_DIFFSERV:
|
||||
rsvp_error_vals = rsvp_diffserv_error_vals;
|
||||
break;
|
||||
case RSVP_ERROR_DSTE:
|
||||
rsvp_error_vals = rsvp_diffserv_aware_te_error_vals;
|
||||
break;
|
||||
}
|
||||
switch (error_code) {
|
||||
case RSVP_ERROR_ADMISSION:
|
||||
|
@ -1923,6 +1979,7 @@ dissect_rsvp_error_value (proto_tree *ti, tvbuff_t *tvb,
|
|||
case RSVP_ERROR_NOTIFY:
|
||||
case RSVP_ERROR_ROUTING:
|
||||
case RSVP_ERROR_DIFFSERV:
|
||||
case RSVP_ERROR_DSTE:
|
||||
if ((error_val & 0xc0) == 0) {
|
||||
proto_tree_add_text(ti, tvb, offset, 2,
|
||||
"Error value: %u - %s", error_val,
|
||||
|
@ -4746,6 +4803,40 @@ dissect_rsvp_diffserv (proto_tree *ti, proto_tree *rsvp_object_tree,
|
|||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* CLASSTYPE
|
||||
*------------------------------------------------------------------------------*/
|
||||
static void
|
||||
dissect_rsvp_diffserv_aware_te(proto_tree *ti, proto_tree *rsvp_object_tree,
|
||||
tvbuff_t *tvb,
|
||||
int offset, int obj_length,
|
||||
int class _U_, int type)
|
||||
{
|
||||
int offset2 = offset + 4;
|
||||
guint8 ct = 0;
|
||||
|
||||
proto_tree_add_item_hidden(rsvp_object_tree,
|
||||
rsvp_filter[RSVPF_DSTE],
|
||||
tvb, offset, 8, FALSE);
|
||||
switch(type) {
|
||||
case 1:
|
||||
ct = tvb_get_guint8(tvb, offset2+3);
|
||||
proto_tree_add_text(rsvp_object_tree, tvb, offset+3, 1, "C-type: 1");
|
||||
proto_tree_add_item(rsvp_object_tree,
|
||||
rsvp_filter[RSVPF_DSTE_CLASSTYPE],
|
||||
tvb, offset2+3, 1, FALSE);
|
||||
proto_item_set_text(ti, "CLASSTYPE: CT %u", ct);
|
||||
break;
|
||||
default:
|
||||
proto_item_set_text(ti, "CLASSTYPE: (Unknown C-type)");
|
||||
proto_tree_add_text(rsvp_object_tree, tvb, offset+3, 1,
|
||||
"C-type: Unknown (%u)", type);
|
||||
proto_tree_add_text(rsvp_object_tree, tvb, offset2, obj_length - 4,
|
||||
"Data (%d bytes)", obj_length - 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Dissect a single RSVP message in a tree
|
||||
*------------------------------------------------------------------------------*/
|
||||
|
@ -5034,6 +5125,10 @@ dissect_rsvp_msg_tree(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
|
|||
dissect_rsvp_diffserv(ti, rsvp_object_tree, tvb, offset, obj_length, class, type);
|
||||
break;
|
||||
|
||||
case RSVP_CLASS_CLASSTYPE:
|
||||
dissect_rsvp_diffserv_aware_te(ti, rsvp_object_tree, tvb, offset, obj_length, class, type);
|
||||
break;
|
||||
|
||||
case RSVP_CLASS_NULL:
|
||||
default:
|
||||
proto_tree_add_text(rsvp_object_tree, tvb, offset2, obj_length - 4,
|
||||
|
|
Loading…
Reference in New Issue