1ad2f8eb0SMartin KaFai Lau // SPDX-License-Identifier: GPL-2.0 2ad2f8eb0SMartin KaFai Lau /* Copyright (c) 2020 Facebook */ 3ad2f8eb0SMartin KaFai Lau 4ad2f8eb0SMartin KaFai Lau #include <stddef.h> 5ad2f8eb0SMartin KaFai Lau #include <errno.h> 6ad2f8eb0SMartin KaFai Lau #include <stdbool.h> 7ad2f8eb0SMartin KaFai Lau #include <sys/types.h> 8ad2f8eb0SMartin KaFai Lau #include <sys/socket.h> 9ad2f8eb0SMartin KaFai Lau #include <linux/ipv6.h> 10ad2f8eb0SMartin KaFai Lau #include <linux/tcp.h> 11ad2f8eb0SMartin KaFai Lau #include <linux/socket.h> 12ad2f8eb0SMartin KaFai Lau #include <linux/bpf.h> 13ad2f8eb0SMartin KaFai Lau #include <linux/types.h> 14ad2f8eb0SMartin KaFai Lau #include <bpf/bpf_helpers.h> 15ad2f8eb0SMartin KaFai Lau #include <bpf/bpf_endian.h> 16ad2f8eb0SMartin KaFai Lau #define BPF_PROG_TEST_TCP_HDR_OPTIONS 17ad2f8eb0SMartin KaFai Lau #include "test_tcp_hdr_options.h" 18ad2f8eb0SMartin KaFai Lau 19ad2f8eb0SMartin KaFai Lau __u16 last_addr16_n = __bpf_htons(0xeB9F); 20ad2f8eb0SMartin KaFai Lau __u16 active_lport_n = 0; 21ad2f8eb0SMartin KaFai Lau __u16 active_lport_h = 0; 22ad2f8eb0SMartin KaFai Lau __u16 passive_lport_n = 0; 23ad2f8eb0SMartin KaFai Lau __u16 passive_lport_h = 0; 24ad2f8eb0SMartin KaFai Lau 25ad2f8eb0SMartin KaFai Lau /* options received at passive side */ 26ad2f8eb0SMartin KaFai Lau unsigned int nr_pure_ack = 0; 27ad2f8eb0SMartin KaFai Lau unsigned int nr_data = 0; 28ad2f8eb0SMartin KaFai Lau unsigned int nr_syn = 0; 29ad2f8eb0SMartin KaFai Lau unsigned int nr_fin = 0; 30ad2f8eb0SMartin KaFai Lau 31ad2f8eb0SMartin KaFai Lau /* Check the header received from the active side */ 32ad2f8eb0SMartin KaFai Lau static int __check_active_hdr_in(struct bpf_sock_ops *skops, bool check_syn) 33ad2f8eb0SMartin KaFai Lau { 34ad2f8eb0SMartin KaFai Lau union { 35ad2f8eb0SMartin KaFai Lau struct tcphdr th; 36ad2f8eb0SMartin KaFai Lau struct ipv6hdr ip6; 37ad2f8eb0SMartin KaFai Lau struct tcp_exprm_opt exprm_opt; 38ad2f8eb0SMartin KaFai Lau struct tcp_opt reg_opt; 39ad2f8eb0SMartin KaFai Lau __u8 data[100]; /* IPv6 (40) + Max TCP hdr (60) */ 40ad2f8eb0SMartin KaFai Lau } hdr = {}; 41ad2f8eb0SMartin KaFai Lau __u64 load_flags = check_syn ? BPF_LOAD_HDR_OPT_TCP_SYN : 0; 42ad2f8eb0SMartin KaFai Lau struct tcphdr *pth; 43ad2f8eb0SMartin KaFai Lau int ret; 44ad2f8eb0SMartin KaFai Lau 45ad2f8eb0SMartin KaFai Lau hdr.reg_opt.kind = 0xB9; 46ad2f8eb0SMartin KaFai Lau 47ad2f8eb0SMartin KaFai Lau /* The option is 4 bytes long instead of 2 bytes */ 48ad2f8eb0SMartin KaFai Lau ret = bpf_load_hdr_opt(skops, &hdr.reg_opt, 2, load_flags); 49ad2f8eb0SMartin KaFai Lau if (ret != -ENOSPC) 50ad2f8eb0SMartin KaFai Lau RET_CG_ERR(ret); 51ad2f8eb0SMartin KaFai Lau 52ad2f8eb0SMartin KaFai Lau /* Test searching magic with regular kind */ 53ad2f8eb0SMartin KaFai Lau hdr.reg_opt.len = 4; 54ad2f8eb0SMartin KaFai Lau ret = bpf_load_hdr_opt(skops, &hdr.reg_opt, sizeof(hdr.reg_opt), 55ad2f8eb0SMartin KaFai Lau load_flags); 56ad2f8eb0SMartin KaFai Lau if (ret != -EINVAL) 57ad2f8eb0SMartin KaFai Lau RET_CG_ERR(ret); 58ad2f8eb0SMartin KaFai Lau 59ad2f8eb0SMartin KaFai Lau hdr.reg_opt.len = 0; 60ad2f8eb0SMartin KaFai Lau ret = bpf_load_hdr_opt(skops, &hdr.reg_opt, sizeof(hdr.reg_opt), 61ad2f8eb0SMartin KaFai Lau load_flags); 62ad2f8eb0SMartin KaFai Lau if (ret != 4 || hdr.reg_opt.len != 4 || hdr.reg_opt.kind != 0xB9 || 63ad2f8eb0SMartin KaFai Lau hdr.reg_opt.data[0] != 0xfa || hdr.reg_opt.data[1] != 0xce) 64ad2f8eb0SMartin KaFai Lau RET_CG_ERR(ret); 65ad2f8eb0SMartin KaFai Lau 66ad2f8eb0SMartin KaFai Lau /* Test searching experimental option with invalid kind length */ 67ad2f8eb0SMartin KaFai Lau hdr.exprm_opt.kind = TCPOPT_EXP; 68ad2f8eb0SMartin KaFai Lau hdr.exprm_opt.len = 5; 69ad2f8eb0SMartin KaFai Lau hdr.exprm_opt.magic = 0; 70ad2f8eb0SMartin KaFai Lau ret = bpf_load_hdr_opt(skops, &hdr.exprm_opt, sizeof(hdr.exprm_opt), 71ad2f8eb0SMartin KaFai Lau load_flags); 72ad2f8eb0SMartin KaFai Lau if (ret != -EINVAL) 73ad2f8eb0SMartin KaFai Lau RET_CG_ERR(ret); 74ad2f8eb0SMartin KaFai Lau 75ad2f8eb0SMartin KaFai Lau /* Test searching experimental option with 0 magic value */ 76ad2f8eb0SMartin KaFai Lau hdr.exprm_opt.len = 4; 77ad2f8eb0SMartin KaFai Lau ret = bpf_load_hdr_opt(skops, &hdr.exprm_opt, sizeof(hdr.exprm_opt), 78ad2f8eb0SMartin KaFai Lau load_flags); 79ad2f8eb0SMartin KaFai Lau if (ret != -ENOMSG) 80ad2f8eb0SMartin KaFai Lau RET_CG_ERR(ret); 81ad2f8eb0SMartin KaFai Lau 82ad2f8eb0SMartin KaFai Lau hdr.exprm_opt.magic = __bpf_htons(0xeB9F); 83ad2f8eb0SMartin KaFai Lau ret = bpf_load_hdr_opt(skops, &hdr.exprm_opt, sizeof(hdr.exprm_opt), 84ad2f8eb0SMartin KaFai Lau load_flags); 85ad2f8eb0SMartin KaFai Lau if (ret != 4 || hdr.exprm_opt.len != 4 || 86ad2f8eb0SMartin KaFai Lau hdr.exprm_opt.kind != TCPOPT_EXP || 87ad2f8eb0SMartin KaFai Lau hdr.exprm_opt.magic != __bpf_htons(0xeB9F)) 88ad2f8eb0SMartin KaFai Lau RET_CG_ERR(ret); 89ad2f8eb0SMartin KaFai Lau 90ad2f8eb0SMartin KaFai Lau if (!check_syn) 91ad2f8eb0SMartin KaFai Lau return CG_OK; 92ad2f8eb0SMartin KaFai Lau 93ad2f8eb0SMartin KaFai Lau /* Test loading from skops->syn_skb if sk_state == TCP_NEW_SYN_RECV 94ad2f8eb0SMartin KaFai Lau * 95ad2f8eb0SMartin KaFai Lau * Test loading from tp->saved_syn for other sk_state. 96ad2f8eb0SMartin KaFai Lau */ 97ad2f8eb0SMartin KaFai Lau ret = bpf_getsockopt(skops, SOL_TCP, TCP_BPF_SYN_IP, &hdr.ip6, 98ad2f8eb0SMartin KaFai Lau sizeof(hdr.ip6)); 99ad2f8eb0SMartin KaFai Lau if (ret != -ENOSPC) 100ad2f8eb0SMartin KaFai Lau RET_CG_ERR(ret); 101ad2f8eb0SMartin KaFai Lau 102ad2f8eb0SMartin KaFai Lau if (hdr.ip6.saddr.s6_addr16[7] != last_addr16_n || 103ad2f8eb0SMartin KaFai Lau hdr.ip6.daddr.s6_addr16[7] != last_addr16_n) 104ad2f8eb0SMartin KaFai Lau RET_CG_ERR(0); 105ad2f8eb0SMartin KaFai Lau 106ad2f8eb0SMartin KaFai Lau ret = bpf_getsockopt(skops, SOL_TCP, TCP_BPF_SYN_IP, &hdr, sizeof(hdr)); 107ad2f8eb0SMartin KaFai Lau if (ret < 0) 108ad2f8eb0SMartin KaFai Lau RET_CG_ERR(ret); 109ad2f8eb0SMartin KaFai Lau 110ad2f8eb0SMartin KaFai Lau pth = (struct tcphdr *)(&hdr.ip6 + 1); 111ad2f8eb0SMartin KaFai Lau if (pth->dest != passive_lport_n || pth->source != active_lport_n) 112ad2f8eb0SMartin KaFai Lau RET_CG_ERR(0); 113ad2f8eb0SMartin KaFai Lau 114ad2f8eb0SMartin KaFai Lau ret = bpf_getsockopt(skops, SOL_TCP, TCP_BPF_SYN, &hdr, sizeof(hdr)); 115ad2f8eb0SMartin KaFai Lau if (ret < 0) 116ad2f8eb0SMartin KaFai Lau RET_CG_ERR(ret); 117ad2f8eb0SMartin KaFai Lau 118ad2f8eb0SMartin KaFai Lau if (hdr.th.dest != passive_lport_n || hdr.th.source != active_lport_n) 119ad2f8eb0SMartin KaFai Lau RET_CG_ERR(0); 120ad2f8eb0SMartin KaFai Lau 121ad2f8eb0SMartin KaFai Lau return CG_OK; 122ad2f8eb0SMartin KaFai Lau } 123ad2f8eb0SMartin KaFai Lau 124ad2f8eb0SMartin KaFai Lau static int check_active_syn_in(struct bpf_sock_ops *skops) 125ad2f8eb0SMartin KaFai Lau { 126ad2f8eb0SMartin KaFai Lau return __check_active_hdr_in(skops, true); 127ad2f8eb0SMartin KaFai Lau } 128ad2f8eb0SMartin KaFai Lau 129ad2f8eb0SMartin KaFai Lau static int check_active_hdr_in(struct bpf_sock_ops *skops) 130ad2f8eb0SMartin KaFai Lau { 131ad2f8eb0SMartin KaFai Lau struct tcphdr *th; 132ad2f8eb0SMartin KaFai Lau 133ad2f8eb0SMartin KaFai Lau if (__check_active_hdr_in(skops, false) == CG_ERR) 134ad2f8eb0SMartin KaFai Lau return CG_ERR; 135ad2f8eb0SMartin KaFai Lau 136ad2f8eb0SMartin KaFai Lau th = skops->skb_data; 137ad2f8eb0SMartin KaFai Lau if (th + 1 > skops->skb_data_end) 138ad2f8eb0SMartin KaFai Lau RET_CG_ERR(0); 139ad2f8eb0SMartin KaFai Lau 140ad2f8eb0SMartin KaFai Lau if (tcp_hdrlen(th) < skops->skb_len) 141ad2f8eb0SMartin KaFai Lau nr_data++; 142ad2f8eb0SMartin KaFai Lau 143ad2f8eb0SMartin KaFai Lau if (th->fin) 144ad2f8eb0SMartin KaFai Lau nr_fin++; 145ad2f8eb0SMartin KaFai Lau 146ad2f8eb0SMartin KaFai Lau if (th->ack && !th->fin && tcp_hdrlen(th) == skops->skb_len) 147ad2f8eb0SMartin KaFai Lau nr_pure_ack++; 148ad2f8eb0SMartin KaFai Lau 149ad2f8eb0SMartin KaFai Lau return CG_OK; 150ad2f8eb0SMartin KaFai Lau } 151ad2f8eb0SMartin KaFai Lau 152ad2f8eb0SMartin KaFai Lau static int active_opt_len(struct bpf_sock_ops *skops) 153ad2f8eb0SMartin KaFai Lau { 154ad2f8eb0SMartin KaFai Lau int err; 155ad2f8eb0SMartin KaFai Lau 156ad2f8eb0SMartin KaFai Lau /* Reserve more than enough to allow the -EEXIST test in 157ad2f8eb0SMartin KaFai Lau * the write_active_opt(). 158ad2f8eb0SMartin KaFai Lau */ 159ad2f8eb0SMartin KaFai Lau err = bpf_reserve_hdr_opt(skops, 12, 0); 160ad2f8eb0SMartin KaFai Lau if (err) 161ad2f8eb0SMartin KaFai Lau RET_CG_ERR(err); 162ad2f8eb0SMartin KaFai Lau 163ad2f8eb0SMartin KaFai Lau return CG_OK; 164ad2f8eb0SMartin KaFai Lau } 165ad2f8eb0SMartin KaFai Lau 166ad2f8eb0SMartin KaFai Lau static int write_active_opt(struct bpf_sock_ops *skops) 167ad2f8eb0SMartin KaFai Lau { 168ad2f8eb0SMartin KaFai Lau struct tcp_exprm_opt exprm_opt = {}; 169ad2f8eb0SMartin KaFai Lau struct tcp_opt win_scale_opt = {}; 170ad2f8eb0SMartin KaFai Lau struct tcp_opt reg_opt = {}; 171ad2f8eb0SMartin KaFai Lau struct tcphdr *th; 172ad2f8eb0SMartin KaFai Lau int err, ret; 173ad2f8eb0SMartin KaFai Lau 174ad2f8eb0SMartin KaFai Lau exprm_opt.kind = TCPOPT_EXP; 175ad2f8eb0SMartin KaFai Lau exprm_opt.len = 4; 176ad2f8eb0SMartin KaFai Lau exprm_opt.magic = __bpf_htons(0xeB9F); 177ad2f8eb0SMartin KaFai Lau 178ad2f8eb0SMartin KaFai Lau reg_opt.kind = 0xB9; 179ad2f8eb0SMartin KaFai Lau reg_opt.len = 4; 180ad2f8eb0SMartin KaFai Lau reg_opt.data[0] = 0xfa; 181ad2f8eb0SMartin KaFai Lau reg_opt.data[1] = 0xce; 182ad2f8eb0SMartin KaFai Lau 183ad2f8eb0SMartin KaFai Lau win_scale_opt.kind = TCPOPT_WINDOW; 184ad2f8eb0SMartin KaFai Lau 185ad2f8eb0SMartin KaFai Lau err = bpf_store_hdr_opt(skops, &exprm_opt, sizeof(exprm_opt), 0); 186ad2f8eb0SMartin KaFai Lau if (err) 187ad2f8eb0SMartin KaFai Lau RET_CG_ERR(err); 188ad2f8eb0SMartin KaFai Lau 189ad2f8eb0SMartin KaFai Lau /* Store the same exprm option */ 190ad2f8eb0SMartin KaFai Lau err = bpf_store_hdr_opt(skops, &exprm_opt, sizeof(exprm_opt), 0); 191ad2f8eb0SMartin KaFai Lau if (err != -EEXIST) 192ad2f8eb0SMartin KaFai Lau RET_CG_ERR(err); 193ad2f8eb0SMartin KaFai Lau 194ad2f8eb0SMartin KaFai Lau err = bpf_store_hdr_opt(skops, ®_opt, sizeof(reg_opt), 0); 195ad2f8eb0SMartin KaFai Lau if (err) 196ad2f8eb0SMartin KaFai Lau RET_CG_ERR(err); 197ad2f8eb0SMartin KaFai Lau err = bpf_store_hdr_opt(skops, ®_opt, sizeof(reg_opt), 0); 198ad2f8eb0SMartin KaFai Lau if (err != -EEXIST) 199ad2f8eb0SMartin KaFai Lau RET_CG_ERR(err); 200ad2f8eb0SMartin KaFai Lau 201ad2f8eb0SMartin KaFai Lau /* Check the option has been written and can be searched */ 202ad2f8eb0SMartin KaFai Lau ret = bpf_load_hdr_opt(skops, &exprm_opt, sizeof(exprm_opt), 0); 203ad2f8eb0SMartin KaFai Lau if (ret != 4 || exprm_opt.len != 4 || exprm_opt.kind != TCPOPT_EXP || 204ad2f8eb0SMartin KaFai Lau exprm_opt.magic != __bpf_htons(0xeB9F)) 205ad2f8eb0SMartin KaFai Lau RET_CG_ERR(ret); 206ad2f8eb0SMartin KaFai Lau 207ad2f8eb0SMartin KaFai Lau reg_opt.len = 0; 208ad2f8eb0SMartin KaFai Lau ret = bpf_load_hdr_opt(skops, ®_opt, sizeof(reg_opt), 0); 209ad2f8eb0SMartin KaFai Lau if (ret != 4 || reg_opt.len != 4 || reg_opt.kind != 0xB9 || 210ad2f8eb0SMartin KaFai Lau reg_opt.data[0] != 0xfa || reg_opt.data[1] != 0xce) 211ad2f8eb0SMartin KaFai Lau RET_CG_ERR(ret); 212ad2f8eb0SMartin KaFai Lau 213ad2f8eb0SMartin KaFai Lau th = skops->skb_data; 214ad2f8eb0SMartin KaFai Lau if (th + 1 > skops->skb_data_end) 215ad2f8eb0SMartin KaFai Lau RET_CG_ERR(0); 216ad2f8eb0SMartin KaFai Lau 217ad2f8eb0SMartin KaFai Lau if (th->syn) { 218ad2f8eb0SMartin KaFai Lau active_lport_h = skops->local_port; 219ad2f8eb0SMartin KaFai Lau active_lport_n = th->source; 220ad2f8eb0SMartin KaFai Lau 221ad2f8eb0SMartin KaFai Lau /* Search the win scale option written by kernel 222ad2f8eb0SMartin KaFai Lau * in the SYN packet. 223ad2f8eb0SMartin KaFai Lau */ 224ad2f8eb0SMartin KaFai Lau ret = bpf_load_hdr_opt(skops, &win_scale_opt, 225ad2f8eb0SMartin KaFai Lau sizeof(win_scale_opt), 0); 226ad2f8eb0SMartin KaFai Lau if (ret != 3 || win_scale_opt.len != 3 || 227ad2f8eb0SMartin KaFai Lau win_scale_opt.kind != TCPOPT_WINDOW) 228ad2f8eb0SMartin KaFai Lau RET_CG_ERR(ret); 229ad2f8eb0SMartin KaFai Lau 230ad2f8eb0SMartin KaFai Lau /* Write the win scale option that kernel 231ad2f8eb0SMartin KaFai Lau * has already written. 232ad2f8eb0SMartin KaFai Lau */ 233ad2f8eb0SMartin KaFai Lau err = bpf_store_hdr_opt(skops, &win_scale_opt, 234ad2f8eb0SMartin KaFai Lau sizeof(win_scale_opt), 0); 235ad2f8eb0SMartin KaFai Lau if (err != -EEXIST) 236ad2f8eb0SMartin KaFai Lau RET_CG_ERR(err); 237ad2f8eb0SMartin KaFai Lau } 238ad2f8eb0SMartin KaFai Lau 239ad2f8eb0SMartin KaFai Lau return CG_OK; 240ad2f8eb0SMartin KaFai Lau } 241ad2f8eb0SMartin KaFai Lau 242ad2f8eb0SMartin KaFai Lau static int handle_hdr_opt_len(struct bpf_sock_ops *skops) 243ad2f8eb0SMartin KaFai Lau { 244ad2f8eb0SMartin KaFai Lau __u8 tcp_flags = skops_tcp_flags(skops); 245ad2f8eb0SMartin KaFai Lau 246ad2f8eb0SMartin KaFai Lau if ((tcp_flags & TCPHDR_SYNACK) == TCPHDR_SYNACK) 247ad2f8eb0SMartin KaFai Lau /* Check the SYN from bpf_sock_ops_kern->syn_skb */ 248ad2f8eb0SMartin KaFai Lau return check_active_syn_in(skops); 249ad2f8eb0SMartin KaFai Lau 250ad2f8eb0SMartin KaFai Lau /* Passive side should have cleared the write hdr cb by now */ 251ad2f8eb0SMartin KaFai Lau if (skops->local_port == passive_lport_h) 252ad2f8eb0SMartin KaFai Lau RET_CG_ERR(0); 253ad2f8eb0SMartin KaFai Lau 254ad2f8eb0SMartin KaFai Lau return active_opt_len(skops); 255ad2f8eb0SMartin KaFai Lau } 256ad2f8eb0SMartin KaFai Lau 257ad2f8eb0SMartin KaFai Lau static int handle_write_hdr_opt(struct bpf_sock_ops *skops) 258ad2f8eb0SMartin KaFai Lau { 259ad2f8eb0SMartin KaFai Lau if (skops->local_port == passive_lport_h) 260ad2f8eb0SMartin KaFai Lau RET_CG_ERR(0); 261ad2f8eb0SMartin KaFai Lau 262ad2f8eb0SMartin KaFai Lau return write_active_opt(skops); 263ad2f8eb0SMartin KaFai Lau } 264ad2f8eb0SMartin KaFai Lau 265ad2f8eb0SMartin KaFai Lau static int handle_parse_hdr(struct bpf_sock_ops *skops) 266ad2f8eb0SMartin KaFai Lau { 267ad2f8eb0SMartin KaFai Lau /* Passive side is not writing any non-standard/unknown 268ad2f8eb0SMartin KaFai Lau * option, so the active side should never be called. 269ad2f8eb0SMartin KaFai Lau */ 270ad2f8eb0SMartin KaFai Lau if (skops->local_port == active_lport_h) 271ad2f8eb0SMartin KaFai Lau RET_CG_ERR(0); 272ad2f8eb0SMartin KaFai Lau 273ad2f8eb0SMartin KaFai Lau return check_active_hdr_in(skops); 274ad2f8eb0SMartin KaFai Lau } 275ad2f8eb0SMartin KaFai Lau 276ad2f8eb0SMartin KaFai Lau static int handle_passive_estab(struct bpf_sock_ops *skops) 277ad2f8eb0SMartin KaFai Lau { 278ad2f8eb0SMartin KaFai Lau int err; 279ad2f8eb0SMartin KaFai Lau 280ad2f8eb0SMartin KaFai Lau /* No more write hdr cb */ 281ad2f8eb0SMartin KaFai Lau bpf_sock_ops_cb_flags_set(skops, 282ad2f8eb0SMartin KaFai Lau skops->bpf_sock_ops_cb_flags & 283ad2f8eb0SMartin KaFai Lau ~BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG); 284ad2f8eb0SMartin KaFai Lau 285ad2f8eb0SMartin KaFai Lau /* Recheck the SYN but check the tp->saved_syn this time */ 286ad2f8eb0SMartin KaFai Lau err = check_active_syn_in(skops); 287ad2f8eb0SMartin KaFai Lau if (err == CG_ERR) 288ad2f8eb0SMartin KaFai Lau return err; 289ad2f8eb0SMartin KaFai Lau 290ad2f8eb0SMartin KaFai Lau nr_syn++; 291ad2f8eb0SMartin KaFai Lau 292ad2f8eb0SMartin KaFai Lau /* The ack has header option written by the active side also */ 293ad2f8eb0SMartin KaFai Lau return check_active_hdr_in(skops); 294ad2f8eb0SMartin KaFai Lau } 295ad2f8eb0SMartin KaFai Lau 296ad2f8eb0SMartin KaFai Lau SEC("sockops/misc_estab") 297ad2f8eb0SMartin KaFai Lau int misc_estab(struct bpf_sock_ops *skops) 298ad2f8eb0SMartin KaFai Lau { 299ad2f8eb0SMartin KaFai Lau int true_val = 1; 300ad2f8eb0SMartin KaFai Lau 301ad2f8eb0SMartin KaFai Lau switch (skops->op) { 302ad2f8eb0SMartin KaFai Lau case BPF_SOCK_OPS_TCP_LISTEN_CB: 303ad2f8eb0SMartin KaFai Lau passive_lport_h = skops->local_port; 304ad2f8eb0SMartin KaFai Lau passive_lport_n = __bpf_htons(passive_lport_h); 305ad2f8eb0SMartin KaFai Lau bpf_setsockopt(skops, SOL_TCP, TCP_SAVE_SYN, 306ad2f8eb0SMartin KaFai Lau &true_val, sizeof(true_val)); 307ad2f8eb0SMartin KaFai Lau set_hdr_cb_flags(skops); 308ad2f8eb0SMartin KaFai Lau break; 309ad2f8eb0SMartin KaFai Lau case BPF_SOCK_OPS_TCP_CONNECT_CB: 310ad2f8eb0SMartin KaFai Lau set_hdr_cb_flags(skops); 311ad2f8eb0SMartin KaFai Lau break; 312ad2f8eb0SMartin KaFai Lau case BPF_SOCK_OPS_PARSE_HDR_OPT_CB: 313ad2f8eb0SMartin KaFai Lau return handle_parse_hdr(skops); 314ad2f8eb0SMartin KaFai Lau case BPF_SOCK_OPS_HDR_OPT_LEN_CB: 315ad2f8eb0SMartin KaFai Lau return handle_hdr_opt_len(skops); 316ad2f8eb0SMartin KaFai Lau case BPF_SOCK_OPS_WRITE_HDR_OPT_CB: 317ad2f8eb0SMartin KaFai Lau return handle_write_hdr_opt(skops); 318ad2f8eb0SMartin KaFai Lau case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: 319ad2f8eb0SMartin KaFai Lau return handle_passive_estab(skops); 320ad2f8eb0SMartin KaFai Lau } 321ad2f8eb0SMartin KaFai Lau 322ad2f8eb0SMartin KaFai Lau return CG_OK; 323ad2f8eb0SMartin KaFai Lau } 324ad2f8eb0SMartin KaFai Lau 325ad2f8eb0SMartin KaFai Lau char _license[] SEC("license") = "GPL"; 326