]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - net/core/filter.c
bpf: allow BPF programs access skb_shared_info->gso_segs field
[linux.git] / net / core / filter.c
index 447dd1bad31fa953e222304e60af5519b2621798..8e587dd1da200494b900bd14eec7f875f5453773 100644 (file)
@@ -4203,7 +4203,7 @@ BPF_CALL_5(bpf_setsockopt, struct bpf_sock_ops_kern *, bpf_sock,
                        /* Only some options are supported */
                        switch (optname) {
                        case TCP_BPF_IW:
-                               if (val <= 0 || tp->data_segs_out > 0)
+                               if (val <= 0 || tp->data_segs_out > tp->syn_data)
                                        ret = -EINVAL;
                                else
                                        tp->snd_cwnd = val;
@@ -6700,6 +6700,27 @@ static u32 bpf_convert_ctx_access(enum bpf_access_type type,
                                                             target_size));
                break;
 
+       case offsetof(struct __sk_buff, gso_segs):
+               /* si->dst_reg = skb_shinfo(SKB); */
+#ifdef NET_SKBUFF_DATA_USES_OFFSET
+               *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, head),
+                                     si->dst_reg, si->src_reg,
+                                     offsetof(struct sk_buff, head));
+               *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, end),
+                                     BPF_REG_AX, si->src_reg,
+                                     offsetof(struct sk_buff, end));
+               *insn++ = BPF_ALU64_REG(BPF_ADD, si->dst_reg, BPF_REG_AX);
+#else
+               *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, end),
+                                     si->dst_reg, si->src_reg,
+                                     offsetof(struct sk_buff, end));
+#endif
+               *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct skb_shared_info, gso_segs),
+                                     si->dst_reg, si->dst_reg,
+                                     bpf_target_off(struct skb_shared_info,
+                                                    gso_segs, 2,
+                                                    target_size));
+               break;
        case offsetof(struct __sk_buff, wire_len):
                BUILD_BUG_ON(FIELD_SIZEOF(struct qdisc_skb_cb, pkt_len) != 4);