Skip to content

Commit 1fc5b59

Browse files
committed
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 62133cb commit 1fc5b59

File tree

3 files changed

+181
-12
lines changed

3 files changed

+181
-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

+171-10
Original file line numberDiff line numberDiff line change
@@ -10041,9 +10041,165 @@ gen_batadv_offsets_v14(compiler_state_t *cstate, bpf_u_int32 type)
1004110041
}
1004210042

1004310043
static void
10044-
gen_batadv_offsets_v15(compiler_state_t *cstate, bpf_u_int32 type)
10044+
gen_prepare_var_offset(compiler_state_t *cstate, bpf_abs_offset *off, struct slist *s)
10045+
{
10046+
struct slist *s2;
10047+
10048+
if (!off->is_variable)
10049+
off->is_variable = 1;
10050+
if (off->reg == -1) {
10051+
off->reg = alloc_reg(cstate);
10052+
10053+
s2 = new_stmt(cstate, BPF_ALU|BPF_AND);
10054+
s2->s.k = 0;
10055+
s2 = new_stmt(cstate, BPF_ST);
10056+
s2->s.k = off->reg;
10057+
sappend(s, s2);
10058+
}
10059+
}
10060+
10061+
/**
10062+
* gen_batadv_loadx_tvlv_len_offset() - load offset to tvlv_len into X
10063+
* @cstate: our compiler state
10064+
* @bat_offset: our offset to the start of the batman-adv packet header
10065+
* @field_offset: offset of tvlv_len field within the batman-adv packet header
10066+
* @s: instructions list to append to
10067+
*
10068+
* Will load: X = bat_offset + field_offset. So that [X] in the packet will
10069+
* point to the most-significant byte of the tvlv_len in a batman-adv packet.
10070+
*/
10071+
static void
10072+
gen_batadv_loadx_tvlv_len_offset(compiler_state_t *cstate,
10073+
bpf_abs_offset *bat_offset,
10074+
bpf_u_int32 field_offset, struct slist *s)
10075+
{
10076+
struct slist *s2;
10077+
10078+
s2 = new_stmt(cstate, BPF_LD|BPF_MEM);
10079+
s2->s.k = bat_offset->reg;
10080+
sappend(s, s2);
10081+
10082+
s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_K);
10083+
s2->s.k = bat_offset->constant_part + field_offset;
10084+
sappend(s, s2);
10085+
10086+
s2 = new_stmt(cstate, BPF_MISC|BPF_TAX);
10087+
s2->s.k = 0;
10088+
sappend(s, s2);
10089+
}
10090+
10091+
/**
10092+
* gen_batadv_loadx_tvlv_len() - load tvlv_len value into X
10093+
* @cstate: our compiler state
10094+
* @bat_offset: our offset to the start of the batman-adv packet header
10095+
* @field_offset: offset of tvlv_len field within the batman-adv packet header
10096+
* @s: instructions list to append to
10097+
*
10098+
* Loads the value of the 2 byte tvlv_len field in a given batman-adv packet
10099+
* header into the X register.
10100+
*/
10101+
static void
10102+
gen_batadv_loadx_tvlv_len(compiler_state_t *cstate, bpf_abs_offset *bat_offset,
10103+
bpf_u_int32 field_offset, struct slist *s)
10104+
{
10105+
struct slist *s2;
10106+
10107+
/* load offset to tvlv_len field into X register */
10108+
gen_batadv_loadx_tvlv_len_offset(cstate, bat_offset, field_offset, s);
10109+
10110+
/* clear A register */
10111+
s2 = new_stmt(cstate, BPF_ALU|BPF_AND|BPF_K);
10112+
s2->s.k = 0;
10113+
sappend(s, s2);
10114+
10115+
/* load most significant byte of tvlv_len */
10116+
s2 = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B);
10117+
s2->s.k = 0;
10118+
sappend(s, s2);
10119+
10120+
/* multiply by 2^8 for real value of MSB, make room for LSB */
10121+
s2 = new_stmt(cstate, BPF_ALU|BPF_LSH|BPF_K);
10122+
s2->s.k = 8;
10123+
sappend(s, s2);
10124+
10125+
/* load least significant byte of tvlv_len */
10126+
s2 = new_stmt(cstate, BPF_LD|BPF_IND|BPF_B);
10127+
s2->s.k = 1;
10128+
sappend(s, s2);
10129+
10130+
s2 = new_stmt(cstate, BPF_MISC|BPF_TAX);
10131+
s2->s.k = 0;
10132+
sappend(s, s2);
10133+
}
10134+
10135+
/**
10136+
* gen_batadv_offset_addx() - add X register to a variable offset
10137+
* @cstate: our compiler state
10138+
* @off: the (variable) offset to add to
10139+
* @s: instructions list to append to
10140+
*
10141+
* Adds the value from the X register to the given variable offset.
10142+
*/
10143+
static void
10144+
gen_batadv_offset_addx(compiler_state_t *cstate, bpf_abs_offset *off,
10145+
struct slist *s)
10146+
{
10147+
struct slist *s2;
10148+
10149+
s2 = new_stmt(cstate, BPF_LD|BPF_MEM);
10150+
s2->s.k = off->reg;
10151+
sappend(s, s2);
10152+
10153+
s2 = new_stmt(cstate, BPF_ALU|BPF_ADD|BPF_X);
10154+
s2->s.k = 0;
10155+
sappend(s, s2);
10156+
10157+
s2 = new_stmt(cstate, BPF_ST);
10158+
s2->s.k = off->reg;
10159+
sappend(s, s2);
10160+
}
10161+
10162+
/**
10163+
* gen_batadv_offsets_add_tvlv_len() - add tvlv_len to payload offsets
10164+
* @cstate: our compiler state
10165+
* @b0: instructions block to add to
10166+
* @field_offset: offset of tvlv_len field within the batman-adv packet header
10167+
*
10168+
* Adds the tvlv_len value from/in a batman-adv packet header to the offsets
10169+
* of cstate->off_linkpl and cstate->off_linktype.
10170+
*
10171+
* Return: The updated instructions block.
10172+
*/
10173+
static struct block *
10174+
gen_batadv_offsets_add_tvlv_len(compiler_state_t *cstate, struct block *b0,
10175+
bpf_u_int32 field_offset)
10176+
{
10177+
struct slist s;
10178+
10179+
s.next = NULL;
10180+
10181+
/* turn constant-only offsets into variable offsets as we need to add
10182+
* variable offset values (tvlv_len) to them later */
10183+
gen_prepare_var_offset(cstate, &cstate->off_linkpl, &s);
10184+
gen_prepare_var_offset(cstate, &cstate->off_linktype, &s);
10185+
10186+
/* load tvlv_len into X register */
10187+
gen_batadv_loadx_tvlv_len(cstate, &cstate->off_linkpl, field_offset, &s);
10188+
10189+
gen_batadv_offset_addx(cstate, &cstate->off_linkpl, &s);
10190+
gen_batadv_offset_addx(cstate, &cstate->off_linktype, &s);
10191+
10192+
sappend(s.next, b0->head->stmts);
10193+
b0->head->stmts = s.next;
10194+
10195+
return b0;
10196+
}
10197+
10198+
static struct block *
10199+
gen_batadv_offsets_v15(compiler_state_t *cstate, struct block *b0, bpf_u_int32 type)
1004510200
{
1004610201
size_t offset;
10202+
size_t field_offset;
1004710203

1004810204
switch (type) {
1004910205
case BATADV_BCAST: /* 0x01 */
@@ -10052,6 +10208,12 @@ gen_batadv_offsets_v15(compiler_state_t *cstate, bpf_u_int32 type)
1005210208
case BATADV_CODED: /* 0x02 */
1005310209
offset = sizeof(struct batadv_coded_packet);
1005410210
break;
10211+
case BATADV_MCAST: /* 0x05 */
10212+
offset = sizeof(struct batadv_mcast_packet);
10213+
field_offset = offsetof(struct batadv_mcast_packet, tvlv_len);
10214+
10215+
b0 = gen_batadv_offsets_add_tvlv_len(cstate, b0, field_offset);
10216+
break;
1005510217
case BATADV_UNICAST: /* 0x40 */
1005610218
offset = sizeof(struct batadv_unicast_packet);
1005710219
break;
@@ -10061,32 +10223,31 @@ gen_batadv_offsets_v15(compiler_state_t *cstate, bpf_u_int32 type)
1006110223
case BATADV_UNICAST_4ADDR: /* 0x42 */
1006210224
offset = sizeof(struct batadv_unicast_4addr_packet);
1006310225
break;
10064-
case BATADV_MCAST: /* 0x05 */
10065-
/* unsupported for now, needs variable offset to
10066-
* take tvlv_len into account
10067-
*/
10068-
/* fall through */
1006910226
default:
1007010227
offset = 0;
1007110228
}
1007210229

1007310230
if (offset)
1007410231
gen_batadv_push_offset(cstate, (u_int)offset);
10232+
10233+
return b0;
1007510234
}
1007610235

10077-
static void
10078-
gen_batadv_offsets(compiler_state_t *cstate, bpf_u_int32 version, bpf_u_int32 type)
10236+
static struct block *
10237+
gen_batadv_offsets(compiler_state_t *cstate, struct block *b0, bpf_u_int32 version, bpf_u_int32 type)
1007910238
{
1008010239
switch (version) {
1008110240
case 14:
1008210241
gen_batadv_offsets_v14(cstate, type);
1008310242
break;
1008410243
case 15:
10085-
gen_batadv_offsets_v15(cstate, type);
10244+
b0 = gen_batadv_offsets_v15(cstate, b0, type);
1008610245
break;
1008710246
default:
1008810247
break;
1008910248
}
10249+
10250+
return b0;
1009010251
}
1009110252

1009210253
struct block *
@@ -10109,7 +10270,7 @@ gen_batadv(compiler_state_t *cstate, bpf_u_int32 version, int has_version,
1010910270

1011010271
if (has_type) {
1011110272
b0 = gen_batadv_check_type(cstate, b0, version, type);
10112-
gen_batadv_offsets(cstate, version, type);
10273+
b0 = gen_batadv_offsets(cstate, b0, version, type);
1011310274
}
1011410275

1011510276
return b0;

pcap-filter.manmisc.in

+2-2
Original file line numberDiff line numberDiff line change
@@ -842,8 +842,8 @@ packet type then it changes the decoding offsets for the remainder of the
842842
expression on the assumption that the packet is a batman-adv packet. For compat
843843
\fIversion\fR 14 these are packet \fItype\fRs \fBunicast\fP, \fBbcast\fP,
844844
\fBunicast-frag\fP, \fBunicast-4addr\fP and \fBcoded\fP. For compat \fIversion\fR
845-
15 these are currently packet \fItype\fRs \fBbcast\fP, \fBcoded\fP, \fBunicast\fP,
846-
\fBunicast-frag\fP and \fBunicast-4addr\fP.
845+
15 these are currently packet \fItype\fRs \fBbcast\fP, \fBcoded\fP, \fBmcast\fP,
846+
\fBunicast\fP, \fBunicast-frag\fP and \fBunicast-4addr\fP.
847847
.IP "\fBiso proto \fIprotocol\fR"
848848
True if the packet is an OSI packet of protocol type \fIprotocol\fP.
849849
\fIProtocol\fP can be a number or one of the names

0 commit comments

Comments
 (0)