Skip to content

Commit e688c38

Browse files
T-Xinfrastation
authored andcommitted
batman-adv: Add offset support to batman-adv mcast packet
The batman-adv multicast packet type has a variable offset for its encapsulated payload frames. The offset depends not only on the batman-adv mcast packet header length but also the length of a potential, variable length TVLV between the batman-adv mcast packet header and the payload. This adds according BPF instructions to take the TVLV length into account for a batman-adv mcast packet and adjusts the payload offset accordingly. Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
1 parent 07ef5f3 commit e688c38

File tree

3 files changed

+182
-12
lines changed

3 files changed

+182
-12
lines changed

batadv_packet.h

+8
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,14 @@ struct batadv_bcast_packet {
5959
uint8_t orig[ETH_ALEN];
6060
};
6161

62+
struct batadv_mcast_packet {
63+
uint8_t packet_type;
64+
uint8_t version;
65+
uint8_t ttl;
66+
uint8_t reserved;
67+
uint8_t tvlv_len[2]; /* 2-byte integral value */
68+
};
69+
6270
struct batadv_coded_packet {
6371
uint8_t packet_type;
6472
uint8_t version;

gencode.c

+172-10
Original file line numberDiff line numberDiff line change
@@ -10197,9 +10197,165 @@ gen_batadv_offsets_v14(compiler_state_t *cstate, bpf_u_int32 type)
1019710197
}
1019810198

1019910199
static void
10200-
gen_batadv_offsets_v15(compiler_state_t *cstate, bpf_u_int32 type)
10200+
gen_prepare_var_offset(compiler_state_t *cstate, bpf_abs_offset *off, struct slist *s)
10201+
{
10202+
struct slist *s2;
10203+
10204+
if (!off->is_variable)
10205+
off->is_variable = 1;
10206+
if (off->reg == -1) {
10207+
off->reg = alloc_reg(cstate);
10208+
10209+
s2 = new_stmt(cstate, BPF_ALU|BPF_AND);
10210+
s2->s.k = 0;
10211+
s2 = new_stmt(cstate, BPF_ST);
10212+
s2->s.k = off->reg;
10213+
sappend(s, s2);
10214+
}
10215+
}
10216+
10217+
/**
10218+
* gen_batadv_loadx_tvlv_len_offset() - load offset to tvlv_len into X
10219+
* @cstate: our compiler state
10220+
* @bat_offset: our offset to the start of the batman-adv packet header
10221+
* @field_offset: offset of tvlv_len field within the batman-adv packet header
10222+
* @s: instructions list to append to
10223+
*
10224+
* Will load: X = bat_offset + field_offset. So that [X] in the packet will
10225+
* point to the most-significant byte of the tvlv_len in a batman-adv packet.
10226+
*/
10227+
static void
10228+
gen_batadv_loadx_tvlv_len_offset(compiler_state_t *cstate,
10229+
bpf_abs_offset *bat_offset,
10230+
bpf_u_int32 field_offset, struct slist *s)
10231+
{
10232+
struct slist *s2;
10233+
10234+
s2 = new_stmt(cstate, BPF_LD|BPF_MEM);
10235+
s2->s.k = bat_offset->reg;
10236+
sappend(s, s2);
10237+
10238+
s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
10239+
s2->s.k = bat_offset->constant_part + field_offset;
10240+
sappend(s, s2);
10241+
10242+
s2 = new_stmt(cstate, BPF_MISC|BPF_TAX);
10243+
s2->s.k = 0;
10244+
sappend(s, s2);
10245+
}
10246+
10247+
/**
10248+
* gen_batadv_loadx_tvlv_len() - load tvlv_len value into X
10249+
* @cstate: our compiler state
10250+
* @bat_offset: our offset to the start of the batman-adv packet header
10251+
* @field_offset: offset of tvlv_len field within the batman-adv packet header
10252+
* @s: instructions list to append to
10253+
*
10254+
* Loads the value of the 2 byte tvlv_len field in a given batman-adv packet
10255+
* header into the X register.
10256+
*/
10257+
static void
10258+
gen_batadv_loadx_tvlv_len(compiler_state_t *cstate, bpf_abs_offset *bat_offset,
10259+
bpf_u_int32 field_offset, struct slist *s)
10260+
{
10261+
struct slist *s2;
10262+
10263+
/* load offset to tvlv_len field into X register */
10264+
gen_batadv_loadx_tvlv_len_offset(cstate, bat_offset, field_offset, s);
10265+
10266+
/* clear A register */
10267+
s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K);
10268+
s2->s.k = 0;
10269+
sappend(s, s2);
10270+
10271+
/* load most significant byte of tvlv_len */
10272+
s2 = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B);
10273+
s2->s.k = 0;
10274+
sappend(s, s2);
10275+
10276+
/* multiply by 2^8 for real value of MSB, make room for LSB */
10277+
s2 = new_stmt(cstate, BPF_ALU|BPF_LSH|BPF_K);
10278+
s2->s.k = 8;
10279+
sappend(s, s2);
10280+
10281+
/* load least significant byte of tvlv_len */
10282+
s2 = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B);
10283+
s2->s.k = 1;
10284+
sappend(s, s2);
10285+
10286+
s2 = new_stmt(cstate, BPF_MISC|BPF_TAX);
10287+
s2->s.k = 0;
10288+
sappend(s, s2);
10289+
}
10290+
10291+
/**
10292+
* gen_batadv_offset_addx() - add X register to a variable offset
10293+
* @cstate: our compiler state
10294+
* @off: the (variable) offset to add to
10295+
* @s: instructions list to append to
10296+
*
10297+
* Adds the value from the X register to the given variable offset.
10298+
*/
10299+
static void
10300+
gen_batadv_offset_addx(compiler_state_t *cstate, bpf_abs_offset *off,
10301+
struct slist *s)
10302+
{
10303+
struct slist *s2;
10304+
10305+
s2 = new_stmt(cstate, BPF_LD|BPF_MEM);
10306+
s2->s.k = off->reg;
10307+
sappend(s, s2);
10308+
10309+
s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X);
10310+
s2->s.k = 0;
10311+
sappend(s, s2);
10312+
10313+
s2 = new_stmt(cstate, BPF_ST);
10314+
s2->s.k = off->reg;
10315+
sappend(s, s2);
10316+
}
10317+
10318+
/**
10319+
* gen_batadv_offsets_add_tvlv_len() - add tvlv_len to payload offsets
10320+
* @cstate: our compiler state
10321+
* @b0: instructions block to add to
10322+
* @field_offset: offset of tvlv_len field within the batman-adv packet header
10323+
*
10324+
* Adds the tvlv_len value from/in a batman-adv packet header to the offsets
10325+
* of cstate->off_linkpl and cstate->off_linktype.
10326+
*
10327+
* Return: The updated instructions block.
10328+
*/
10329+
static struct block *
10330+
gen_batadv_offsets_add_tvlv_len(compiler_state_t *cstate, struct block *b0,
10331+
bpf_u_int32 field_offset)
10332+
{
10333+
struct slist s;
10334+
10335+
s.next = NULL;
10336+
10337+
/* turn constant-only offsets into variable offsets as we need to add
10338+
* variable offset values (tvlv_len) to them later */
10339+
gen_prepare_var_offset(cstate, &cstate->off_linkpl, &s);
10340+
gen_prepare_var_offset(cstate, &cstate->off_linktype, &s);
10341+
10342+
/* load tvlv_len into X register */
10343+
gen_batadv_loadx_tvlv_len(cstate, &cstate->off_linkpl, field_offset, &s);
10344+
10345+
gen_batadv_offset_addx(cstate, &cstate->off_linkpl, &s);
10346+
gen_batadv_offset_addx(cstate, &cstate->off_linktype, &s);
10347+
10348+
sappend(s.next, b0->head->stmts);
10349+
b0->head->stmts = s.next;
10350+
10351+
return b0;
10352+
}
10353+
10354+
static struct block *
10355+
gen_batadv_offsets_v15(compiler_state_t *cstate, struct block *b0, bpf_u_int32 type)
1020110356
{
1020210357
size_t offset;
10358+
bpf_u_int32 field_offset;
1020310359

1020410360
switch (type) {
1020510361
case BATADV_BCAST: /* 0x01 */
@@ -10208,6 +10364,13 @@ gen_batadv_offsets_v15(compiler_state_t *cstate, bpf_u_int32 type)
1020810364
case BATADV_CODED: /* 0x02 */
1020910365
offset = sizeof(struct batadv_coded_packet);
1021010366
break;
10367+
case BATADV_MCAST: /* 0x05 */
10368+
offset = sizeof(struct batadv_mcast_packet);
10369+
field_offset = (bpf_u_int32)offsetof(struct batadv_mcast_packet,
10370+
tvlv_len);
10371+
10372+
b0 = gen_batadv_offsets_add_tvlv_len(cstate, b0, field_offset);
10373+
break;
1021110374
case BATADV_UNICAST: /* 0x40 */
1021210375
offset = sizeof(struct batadv_unicast_packet);
1021310376
break;
@@ -10217,32 +10380,31 @@ gen_batadv_offsets_v15(compiler_state_t *cstate, bpf_u_int32 type)
1021710380
case BATADV_UNICAST_4ADDR: /* 0x42 */
1021810381
offset = sizeof(struct batadv_unicast_4addr_packet);
1021910382
break;
10220-
case BATADV_MCAST: /* 0x05 */
10221-
/* unsupported for now, needs variable offset to
10222-
* take tvlv_len into account
10223-
*/
10224-
/* fall through */
1022510383
default:
1022610384
offset = 0;
1022710385
}
1022810386

1022910387
if (offset)
1023010388
gen_batadv_push_offset(cstate, (u_int)offset);
10389+
10390+
return b0;
1023110391
}
1023210392

10233-
static void
10234-
gen_batadv_offsets(compiler_state_t *cstate, bpf_u_int32 version, bpf_u_int32 type)
10393+
static struct block *
10394+
gen_batadv_offsets(compiler_state_t *cstate, struct block *b0, bpf_u_int32 version, bpf_u_int32 type)
1023510395
{
1023610396
switch (version) {
1023710397
case 14:
1023810398
gen_batadv_offsets_v14(cstate, type);
1023910399
break;
1024010400
case 15:
10241-
gen_batadv_offsets_v15(cstate, type);
10401+
b0 = gen_batadv_offsets_v15(cstate, b0, type);
1024210402
break;
1024310403
default:
1024410404
break;
1024510405
}
10406+
10407+
return b0;
1024610408
}
1024710409

1024810410
struct block *
@@ -10265,7 +10427,7 @@ gen_batadv(compiler_state_t *cstate, bpf_u_int32 version, int has_version,
1026510427

1026610428
if (has_type) {
1026710429
b0 = gen_batadv_check_type(cstate, b0, version, type);
10268-
gen_batadv_offsets(cstate, version, type);
10430+
b0 = gen_batadv_offsets(cstate, b0, version, type);
1026910431
}
1027010432

1027110433
return b0;

pcap-filter.manmisc.in

+2-2
Original file line numberDiff line numberDiff line change
@@ -887,8 +887,8 @@ packet type then it changes the decoding offsets for the remainder of the
887887
expression on the assumption that the packet is a batman-adv packet. For compat
888888
\fIversion\fR 14 these are packet \fItype\fRs \fBunicast\fP, \fBbcast\fP,
889889
\fBunicast-frag\fP, \fBunicast-4addr\fP and \fBcoded\fP. For compat \fIversion\fR
890-
15 these are currently packet \fItype\fRs \fBbcast\fP, \fBcoded\fP, \fBunicast\fP,
891-
\fBunicast-frag\fP and \fBunicast-4addr\fP.
890+
15 these are currently packet \fItype\fRs \fBbcast\fP, \fBcoded\fP, \fBmcast\fP,
891+
\fBunicast\fP, \fBunicast-frag\fP and \fBunicast-4addr\fP.
892892
.IP "\fBiso proto \fIprotocol\fR"
893893
True if the packet is an OSI packet of protocol type \fIprotocol\fP.
894894
\fIProtocol\fP can be a number or one of the names

0 commit comments

Comments
 (0)