Line data Source code
1 : /* SPDX-License-Identifier: GPL-2.0-only */
2 : /*
3 : * Copyright (c) 2022 Meta Platforms, Inc. and affiliates.
4 : */
5 :
6 : #include <linux/bpf.h>
7 : #include <linux/bpf_common.h>
8 : #include <linux/icmp.h>
9 : #include <linux/icmpv6.h>
10 :
11 : #include <errno.h>
12 :
13 : #include "bpfilter/cgen/program.h"
14 : #include "core/matcher.h"
15 :
16 0 : static int _bf_matcher_generate_icmp_fields(struct bf_program *program,
17 : const struct bf_matcher *matcher,
18 : const size_t offset)
19 : {
20 0 : const uint8_t value = matcher->payload[0];
21 :
22 0 : EMIT(program, BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_6, offset));
23 :
24 0 : switch (matcher->op) {
25 0 : case BF_MATCHER_EQ:
26 0 : EMIT_FIXUP_JMP_NEXT_RULE(program,
27 : BPF_JMP_IMM(BPF_JNE, BPF_REG_1, value, 0));
28 0 : break;
29 0 : case BF_MATCHER_NE:
30 0 : EMIT_FIXUP_JMP_NEXT_RULE(program,
31 : BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, value, 0));
32 0 : break;
33 0 : default:
34 0 : return bf_err_r(-EINVAL, "unknown matcher operator '%s' (%d)",
35 : bf_matcher_op_to_str(matcher->op), matcher->op);
36 : }
37 :
38 : return 0;
39 : }
40 :
41 0 : static int _bf_matcher_generate_icmp6_fields(struct bf_program *program,
42 : const struct bf_matcher *matcher)
43 : {
44 0 : size_t offset = matcher->type == BF_MATCHER_ICMPV6_TYPE ?
45 0 : offsetof(struct icmp6hdr, icmp6_type) :
46 : offsetof(struct icmp6hdr, icmp6_code);
47 :
48 0 : EMIT_FIXUP_JMP_NEXT_RULE(
49 : program, BPF_JMP_IMM(BPF_JNE, BPF_REG_8, IPPROTO_ICMPV6, 0));
50 0 : EMIT(program,
51 : BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_10, BF_PROG_CTX_OFF(l4_hdr)));
52 :
53 0 : return _bf_matcher_generate_icmp_fields(program, matcher, offset);
54 : }
55 :
56 0 : static int _bf_matcher_generate_icmp4_fields(struct bf_program *program,
57 : const struct bf_matcher *matcher)
58 : {
59 0 : size_t offset = matcher->type == BF_MATCHER_ICMP_TYPE ?
60 0 : offsetof(struct icmphdr, type) :
61 : offsetof(struct icmphdr, code);
62 :
63 0 : EMIT_FIXUP_JMP_NEXT_RULE(program,
64 : BPF_JMP_IMM(BPF_JNE, BPF_REG_8, IPPROTO_ICMP, 0));
65 0 : EMIT(program,
66 : BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_10, BF_PROG_CTX_OFF(l4_hdr)));
67 :
68 0 : return _bf_matcher_generate_icmp_fields(program, matcher, offset);
69 : }
70 :
71 0 : int bf_matcher_generate_icmp(struct bf_program *program,
72 : const struct bf_matcher *matcher)
73 : {
74 : int r;
75 :
76 0 : switch (matcher->type) {
77 0 : case BF_MATCHER_ICMP_TYPE:
78 : case BF_MATCHER_ICMP_CODE:
79 0 : r = _bf_matcher_generate_icmp4_fields(program, matcher);
80 0 : break;
81 0 : case BF_MATCHER_ICMPV6_TYPE:
82 : case BF_MATCHER_ICMPV6_CODE:
83 0 : r = _bf_matcher_generate_icmp6_fields(program, matcher);
84 0 : break;
85 0 : default:
86 0 : return bf_err_r(-EINVAL, "unknown matcher type %d", matcher->type);
87 : };
88 :
89 : return r;
90 : }
|