Skip to content

Commit

Permalink
Use a 16-bit comparison for "dpc".
Browse files Browse the repository at this point in the history
In gen_mtp3field_code_internal() it is not immediately clear what the
OPC value processing code does and whether it does it correctly.  I have
verified that it combines byte swapping and bit shifting and indeed
processes the value consistently with the specification.  To make it
easier to follow in future, replace the custom code and the custom
bitmask with a combination of SWAPLONG() and a bitwise shift.  The
resulting bytecode remains intact (thus no OPC tests change).

The DPC value processing code is plain byte swapping with no bitwise
shift.  The comparison uses BPF_W, but DPC spans only two adjacent
bytes, so change it to BPF_H and use SWAPSHORT(), similar to the above.
The resulting bytecode has the same effect (no DPC apply tests change),
but the SNR becomes better, which is the only change in the
corresponding DPC accept tests, e.g.:

-(000) ld       [4]
-(001) and      #0xff3f0000
-(002) jeq      #0xd6310000      jt 3    jf 4
+(000) ldh      [4]
+(001) and      #0xff3f
+(002) jeq      #0xd631          jt 3    jf 4

The SLS value processing code already uses BPF_B, so just reformat it
along the same lines.  The resulting bytecode remains intact (thus no
SLS tests change).

All of the above applies the same to the HSL variants ("hdpc", "hopc"
and "hsls"), which differ by the field offsets only.  Add comments to
explain the updated code and replace several hard-coded values with
named constants.
  • Loading branch information
infrastation committed Jan 30, 2025
1 parent 62979bf commit 2aebf46
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 97 deletions.
110 changes: 67 additions & 43 deletions gencode.c
Original file line number Diff line number Diff line change
Expand Up @@ -10451,12 +10451,19 @@ gen_mtp2type_abbrev(compiler_state_t *cstate, int type)
return b0;
}

/*
* These maximum valid values are all-ones, so they double as the bitmasks
* before any bitwise shifting.
*/
#define MTP2_SIO_MAXVAL UINT8_MAX
#define MTP3_PC_MAXVAL 0x3fffU
#define MTP3_SLS_MAXVAL 0xfU

static struct block *
gen_mtp3field_code_internal(compiler_state_t *cstate, int mtp3field,
bpf_u_int32 jvalue, int jtype, int reverse)
{
struct block *b0;
bpf_u_int32 val1 , val2 , val3;
u_int newoff_sio;
u_int newoff_opc;
u_int newoff_dpc;
Expand All @@ -10468,43 +10475,70 @@ gen_mtp3field_code_internal(compiler_state_t *cstate, int mtp3field,
newoff_sls = cstate->off_sls;
switch (mtp3field) {

/*
* See UTU-T Rec. Q.703, Section 2.2, Figure 3/Q.703.
*
* SIO is the simplest field: the size is one byte and the offset is a
* multiple of bytes, so the only detail to get right is the value of
* the [right-to-left] field offset.
*/
case MH_SIO:
newoff_sio += 3; /* offset for MTP2_HSL */
/* FALLTHROUGH */

case M_SIO:
if (cstate->off_sio == OFFSET_NOT_SET)
bpf_error(cstate, "'sio' supported only on SS7");
/* sio coded on 1 byte so max value 255 */
if(jvalue > 255)
bpf_error(cstate, "sio value %u too big; max value = 255",
jvalue);
b0 = gen_ncmp(cstate, OR_PACKET, newoff_sio, BPF_B, 0xffffffffU,
if(jvalue > MTP2_SIO_MAXVAL)
bpf_error(cstate, "sio value %u too big; max value = %u",
jvalue, MTP2_SIO_MAXVAL);
// Here the bitmask means "do not apply a bitmask".
b0 = gen_ncmp(cstate, OR_PACKET, newoff_sio, BPF_B, UINT32_MAX,
jtype, reverse, jvalue);
break;

/*
* See UTU-T Rec. Q.704, Section 2.2, Figure 3/Q.704.
*
* SLS, OPC and DPC are more complicated: none of these is sized in a
* multiple of 8 bits, MTP3 encoding is little-endian and MTP packet
* diagrams are meant to be read right-to-left. This means in the
* diagrams within individual fields and concatenations thereof
* bitwise shifts and masks can be noted in the common left-to-right
* manner until each final value is ready to be byte-swapped and
* handed to gen_ncmp(). See also gen_dnhostop(), which solves a
* similar problem in a similar way.
*
* Offsets of fields within the packet header always have the
* right-to-left meaning. Note that in DLT_MTP2 and possibly other
* DLTs the offset does not include the F (Flag) field at the
* beginning of each message.
*
* For example, if the 8-bit SIO field has a 3 byte [RTL] offset, the
* 32-bit standard routing header has a 4 byte [RTL] offset and could
* be tested entirely using a single BPF_W comparison. In this case
* the 14-bit DPC field [LTR] bitmask would be 0x3FFF, the 14-bit OPC
* field [LTR] bitmask would be (0x3FFF << 14) and the 4-bit SLS field
* [LTR] bitmask would be (0xF << 28), all of which conveniently
* correlates with the [RTL] packet diagram until the byte-swapping is
* done before use.
*
* The code below uses this approach for OPC, which spans 3 bytes.
* DPC and SLS use shorter loads, SLS also uses a different offset.
*/
case MH_OPC:
newoff_opc += 3;

/* FALLTHROUGH */
case M_OPC:
if (cstate->off_opc == OFFSET_NOT_SET)
bpf_error(cstate, "'opc' supported only on SS7");
/* opc coded on 14 bits so max value 16383 */
if (jvalue > 16383)
bpf_error(cstate, "opc value %u too big; max value = 16383",
jvalue);
/* the following instructions are made to convert jvalue
* to the form used to write opc in an ss7 message*/
val1 = jvalue & 0x00003c00;
val1 = val1 >>10;
val2 = jvalue & 0x000003fc;
val2 = val2 <<6;
val3 = jvalue & 0x00000003;
val3 = val3 <<22;
jvalue = val1 + val2 + val3;
b0 = gen_ncmp(cstate, OR_PACKET, newoff_opc, BPF_W, 0x00c0ff0fU,
jtype, reverse, jvalue);
if (jvalue > MTP3_PC_MAXVAL)
bpf_error(cstate, "opc value %u too big; max value = %u",
jvalue, MTP3_PC_MAXVAL);
b0 = gen_ncmp(cstate, OR_PACKET, newoff_opc, BPF_W,
SWAPLONG(MTP3_PC_MAXVAL << 14), jtype, reverse,
SWAPLONG(jvalue << 14));
break;

case MH_DPC:
Expand All @@ -10514,19 +10548,12 @@ gen_mtp3field_code_internal(compiler_state_t *cstate, int mtp3field,
case M_DPC:
if (cstate->off_dpc == OFFSET_NOT_SET)
bpf_error(cstate, "'dpc' supported only on SS7");
/* dpc coded on 14 bits so max value 16383 */
if (jvalue > 16383)
bpf_error(cstate, "dpc value %u too big; max value = 16383",
jvalue);
/* the following instructions are made to convert jvalue
* to the forme used to write dpc in an ss7 message*/
val1 = jvalue & 0x000000ff;
val1 = val1 << 24;
val2 = jvalue & 0x00003f00;
val2 = val2 << 8;
jvalue = val1 + val2;
b0 = gen_ncmp(cstate, OR_PACKET, newoff_dpc, BPF_W, 0xff3f0000U,
jtype, reverse, jvalue);
if (jvalue > MTP3_PC_MAXVAL)
bpf_error(cstate, "dpc value %u too big; max value = %u",
jvalue, MTP3_PC_MAXVAL);
b0 = gen_ncmp(cstate, OR_PACKET, newoff_dpc, BPF_H,
SWAPSHORT(MTP3_PC_MAXVAL), jtype, reverse,
SWAPSHORT(jvalue));
break;

case MH_SLS:
Expand All @@ -10536,15 +10563,12 @@ gen_mtp3field_code_internal(compiler_state_t *cstate, int mtp3field,
case M_SLS:
if (cstate->off_sls == OFFSET_NOT_SET)
bpf_error(cstate, "'sls' supported only on SS7");
/* sls coded on 4 bits so max value 15 */
if (jvalue > 15)
bpf_error(cstate, "sls value %u too big; max value = 15",
jvalue);
/* the following instruction is made to convert jvalue
* to the forme used to write sls in an ss7 message*/
jvalue = jvalue << 4;
b0 = gen_ncmp(cstate, OR_PACKET, newoff_sls, BPF_B, 0xf0U,
jtype, reverse, jvalue);
if (jvalue > MTP3_SLS_MAXVAL)
bpf_error(cstate, "sls value %u too big; max value = %u",
jvalue, MTP3_SLS_MAXVAL);
b0 = gen_ncmp(cstate, OR_PACKET, newoff_sls, BPF_B,
MTP3_SLS_MAXVAL << 4, jtype, reverse,
jvalue << 4);
break;

default:
Expand Down
108 changes: 54 additions & 54 deletions testprogs/TESTrun
Original file line number Diff line number Diff line change
Expand Up @@ -653,9 +653,9 @@ my %accept_blocks = (
'dpc (0x31d6 or 0x31d6)',
],
opt => <<~'EOF',
(000) ld [4]
(001) and #0xff3f0000
(002) jeq #0xd6310000 jt 3 jf 4
(000) ldh [4]
(001) and #0xff3f
(002) jeq #0xd631 jt 3 jf 4
(003) ret #262144
(004) ret #0
EOF
Expand All @@ -664,9 +664,9 @@ my %accept_blocks = (
DLT => 'MTP2',
expr => 'dpc > 0x1273',
unopt => <<~'EOF',
(000) ld [4]
(001) and #0xff3f0000
(002) jgt #0x73120000 jt 3 jf 4
(000) ldh [4]
(001) and #0xff3f
(002) jgt #0x7312 jt 3 jf 4
(003) ret #262144
(004) ret #0
EOF
Expand All @@ -675,9 +675,9 @@ my %accept_blocks = (
DLT => 'MTP2',
expr => 'dpc >= 0x1273',
unopt => <<~'EOF',
(000) ld [4]
(001) and #0xff3f0000
(002) jge #0x73120000 jt 3 jf 4
(000) ldh [4]
(001) and #0xff3f
(002) jge #0x7312 jt 3 jf 4
(003) ret #262144
(004) ret #0
EOF
Expand All @@ -686,9 +686,9 @@ my %accept_blocks = (
DLT => 'MTP2',
expr => 'dpc <= 0x1273',
unopt => <<~'EOF',
(000) ld [4]
(001) and #0xff3f0000
(002) jgt #0x73120000 jt 3 jf 4
(000) ldh [4]
(001) and #0xff3f
(002) jgt #0x7312 jt 3 jf 4
(003) ret #0
(004) ret #262144
EOF
Expand All @@ -697,9 +697,9 @@ my %accept_blocks = (
DLT => 'MTP2',
expr => 'dpc < 0x1273',
unopt => <<~'EOF',
(000) ld [4]
(001) and #0xff3f0000
(002) jge #0x73120000 jt 3 jf 4
(000) ldh [4]
(001) and #0xff3f
(002) jge #0x7312 jt 3 jf 4
(003) ret #0
(004) ret #262144
EOF
Expand All @@ -708,9 +708,9 @@ my %accept_blocks = (
DLT => 'MTP2',
expr => 'dpc != 0x1273',
unopt => <<~'EOF',
(000) ld [4]
(001) and #0xff3f0000
(002) jeq #0x73120000 jt 3 jf 4
(000) ldh [4]
(001) and #0xff3f
(002) jeq #0x7312 jt 3 jf 4
(003) ret #0
(004) ret #262144
EOF
Expand All @@ -719,15 +719,15 @@ my %accept_blocks = (
DLT => 'MTP2',
expr => 'dpc (0x1274 or 0x1275 or 0x1276)',
unopt => <<~'EOF',
(000) ld [4]
(001) and #0xff3f0000
(002) jeq #0x74120000 jt 9 jf 3
(003) ld [4]
(004) and #0xff3f0000
(005) jeq #0x75120000 jt 9 jf 6
(006) ld [4]
(007) and #0xff3f0000
(008) jeq #0x76120000 jt 9 jf 10
(000) ldh [4]
(001) and #0xff3f
(002) jeq #0x7412 jt 9 jf 3
(003) ldh [4]
(004) and #0xff3f
(005) jeq #0x7512 jt 9 jf 6
(006) ldh [4]
(007) and #0xff3f
(008) jeq #0x7612 jt 9 jf 10
(009) ret #262144
(010) ret #0
EOF
Expand Down Expand Up @@ -1033,9 +1033,9 @@ my %accept_blocks = (
'hdpc (0x0ab5 or 0x0ab5)',
],
opt => <<~'EOF',
(000) ld [7]
(001) and #0xff3f0000
(002) jeq #0xb50a0000 jt 3 jf 4
(000) ldh [7]
(001) and #0xff3f
(002) jeq #0xb50a jt 3 jf 4
(003) ret #262144
(004) ret #0
EOF
Expand All @@ -1044,9 +1044,9 @@ my %accept_blocks = (
DLT => 'MTP2',
expr => 'hdpc > 0x0ab5',
unopt => <<~'EOF',
(000) ld [7]
(001) and #0xff3f0000
(002) jgt #0xb50a0000 jt 3 jf 4
(000) ldh [7]
(001) and #0xff3f
(002) jgt #0xb50a jt 3 jf 4
(003) ret #262144
(004) ret #0
EOF
Expand All @@ -1055,9 +1055,9 @@ my %accept_blocks = (
DLT => 'MTP2',
expr => 'hdpc >= 0x0ab5',
unopt => <<~'EOF',
(000) ld [7]
(001) and #0xff3f0000
(002) jge #0xb50a0000 jt 3 jf 4
(000) ldh [7]
(001) and #0xff3f
(002) jge #0xb50a jt 3 jf 4
(003) ret #262144
(004) ret #0
EOF
Expand All @@ -1066,9 +1066,9 @@ my %accept_blocks = (
DLT => 'MTP2',
expr => 'hdpc <= 0x0ab5',
unopt => <<~'EOF',
(000) ld [7]
(001) and #0xff3f0000
(002) jgt #0xb50a0000 jt 3 jf 4
(000) ldh [7]
(001) and #0xff3f
(002) jgt #0xb50a jt 3 jf 4
(003) ret #0
(004) ret #262144
EOF
Expand All @@ -1077,9 +1077,9 @@ my %accept_blocks = (
DLT => 'MTP2',
expr => 'hdpc < 0x0ab5',
unopt => <<~'EOF',
(000) ld [7]
(001) and #0xff3f0000
(002) jge #0xb50a0000 jt 3 jf 4
(000) ldh [7]
(001) and #0xff3f
(002) jge #0xb50a jt 3 jf 4
(003) ret #0
(004) ret #262144
EOF
Expand All @@ -1088,9 +1088,9 @@ my %accept_blocks = (
DLT => 'MTP2',
expr => 'hdpc != 0x0ab5',
unopt => <<~'EOF',
(000) ld [7]
(001) and #0xff3f0000
(002) jeq #0xb50a0000 jt 3 jf 4
(000) ldh [7]
(001) and #0xff3f
(002) jeq #0xb50a jt 3 jf 4
(003) ret #0
(004) ret #262144
EOF
Expand All @@ -1099,15 +1099,15 @@ my %accept_blocks = (
DLT => 'MTP2',
expr => 'hdpc (0x0ab6 or 0x0ab7 or 0x0ab8)',
unopt => <<~'EOF',
(000) ld [7]
(001) and #0xff3f0000
(002) jeq #0xb60a0000 jt 9 jf 3
(003) ld [7]
(004) and #0xff3f0000
(005) jeq #0xb70a0000 jt 9 jf 6
(006) ld [7]
(007) and #0xff3f0000
(008) jeq #0xb80a0000 jt 9 jf 10
(000) ldh [7]
(001) and #0xff3f
(002) jeq #0xb60a jt 9 jf 3
(003) ldh [7]
(004) and #0xff3f
(005) jeq #0xb70a jt 9 jf 6
(006) ldh [7]
(007) and #0xff3f
(008) jeq #0xb80a jt 9 jf 10
(009) ret #262144
(010) ret #0
EOF
Expand Down

0 comments on commit 2aebf46

Please sign in to comment.