148156Sjlemon// SPDX-License-Identifier: GPL-2.0 257828Sjlemon/* Copyright (c) 2020 Facebook */ 348156Sjlemon 448156Sjlemon#include <stddef.h> 548156Sjlemon#include <errno.h> 648156Sjlemon#include <stdbool.h> 748156Sjlemon#include <sys/types.h> 848156Sjlemon#include <sys/socket.h> 948156Sjlemon#include <linux/tcp.h> 1048156Sjlemon#include <linux/socket.h> 1148156Sjlemon#include <linux/bpf.h> 1248156Sjlemon#include <linux/types.h> 1348156Sjlemon#include <bpf/bpf_helpers.h> 1448156Sjlemon#include <bpf/bpf_endian.h> 1548156Sjlemon#define BPF_PROG_TEST_TCP_HDR_OPTIONS 1648156Sjlemon#include "test_tcp_hdr_options.h" 1748156Sjlemon 1848156Sjlemon#ifndef sizeof_field 1948156Sjlemon#define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER)) 2048156Sjlemon#endif 2148156Sjlemon 2248156Sjlemon__u8 test_kind = TCPOPT_EXP; 2348156Sjlemon__u16 test_magic = 0xeB9F; 2448156Sjlemon__u32 inherit_cb_flags = 0; 2548156Sjlemon 2650477Speterstruct bpf_test_option passive_synack_out = {}; 2748156Sjlemonstruct bpf_test_option passive_fin_out = {}; 2848156Sjlemon 2948156Sjlemonstruct bpf_test_option passive_estab_in = {}; 3048156Sjlemonstruct bpf_test_option passive_fin_in = {}; 3148156Sjlemon 3248156Sjlemonstruct bpf_test_option active_syn_out = {}; 3348156Sjlemonstruct bpf_test_option active_fin_out = {}; 3457828Sjlemon 3548156Sjlemonstruct bpf_test_option active_estab_in = {}; 36124471Smdoddstruct bpf_test_option active_fin_in = {}; 37124471Smdodd 38124471Smdoddstruct { 39124471Smdodd __uint(type, BPF_MAP_TYPE_SK_STORAGE); 40124471Smdodd __uint(map_flags, BPF_F_NO_PREALLOC); 41124471Smdodd __type(key, int); 42124471Smdodd __type(value, struct hdr_stg); 43124471Smdodd} hdr_stg_map SEC(".maps"); 44124471Smdodd 45124471Smdoddstatic bool skops_want_cookie(const struct bpf_sock_ops *skops) 4657828Sjlemon{ 47124471Smdodd return skops->args[0] == BPF_WRITE_HDR_TCP_SYNACK_COOKIE; 48124471Smdodd} 4957828Sjlemon 5057828Sjlemonstatic bool skops_current_mss(const struct bpf_sock_ops *skops) 5157828Sjlemon{ 5257828Sjlemon return skops->args[0] == BPF_WRITE_HDR_TCP_CURRENT_MSS; 53124471Smdodd} 54124471Smdodd 55124471Smdoddstatic __u8 option_total_len(__u8 flags) 56124471Smdodd{ 57124471Smdodd __u8 i, len = 1; /* +1 for flags */ 5848156Sjlemon 5948156Sjlemon if (!flags) 6057828Sjlemon return 0; 6148156Sjlemon 62124471Smdodd /* RESEND bit does not use a byte */ 63124471Smdodd for (i = OPTION_RESEND + 1; i < __NR_OPTION_FLAGS; i++) 6448156Sjlemon len += !!TEST_OPTION_FLAGS(flags, i); 6548156Sjlemon 6657828Sjlemon if (test_kind == TCPOPT_EXP) 6757828Sjlemon return len + TCP_BPF_EXPOPT_BASE_LEN; 68124471Smdodd else 69124471Smdodd return len + 2; /* +1 kind, +1 kind-len */ 70124471Smdodd} 71124471Smdodd 7257828Sjlemonstatic void write_test_option(const struct bpf_test_option *test_opt, 7357828Sjlemon __u8 *data) 7457828Sjlemon{ 7557828Sjlemon __u8 offset = 0; 76124471Smdodd 77124471Smdodd data[offset++] = test_opt->flags; 78124471Smdodd if (TEST_OPTION_FLAGS(test_opt->flags, OPTION_MAX_DELACK_MS)) 7957828Sjlemon data[offset++] = test_opt->max_delack_ms; 8057828Sjlemon 8148156Sjlemon if (TEST_OPTION_FLAGS(test_opt->flags, OPTION_RAND)) 8248156Sjlemon data[offset++] = test_opt->rand; 83124539Smdodd} 84124539Smdodd 85124539Smdoddstatic int store_option(struct bpf_sock_ops *skops, 86124471Smdodd const struct bpf_test_option *test_opt) 8748156Sjlemon{ 8848156Sjlemon union { 89144991Smdodd struct tcp_exprm_opt exprm; 9048156Sjlemon struct tcp_opt regular; 91124539Smdodd } write_opt; 92124539Smdodd int err; 93124539Smdodd 94124539Smdodd if (test_kind == TCPOPT_EXP) { 95124539Smdodd write_opt.exprm.kind = TCPOPT_EXP; 96124539Smdodd write_opt.exprm.len = option_total_len(test_opt->flags); 97124539Smdodd write_opt.exprm.magic = __bpf_htons(test_magic); 98124539Smdodd write_opt.exprm.data32 = 0; 99124539Smdodd write_test_option(test_opt, write_opt.exprm.data); 100124539Smdodd err = bpf_store_hdr_opt(skops, &write_opt.exprm, 101124539Smdodd sizeof(write_opt.exprm), 0); 102124539Smdodd } else { 103144992Smdodd write_opt.regular.kind = test_kind; 104124539Smdodd write_opt.regular.len = option_total_len(test_opt->flags); 105124539Smdodd write_opt.regular.data32 = 0; 106144992Smdodd write_test_option(test_opt, write_opt.regular.data); 107144992Smdodd err = bpf_store_hdr_opt(skops, &write_opt.regular, 108144992Smdodd sizeof(write_opt.regular), 0); 109144992Smdodd } 110144992Smdodd 111144992Smdodd if (err) 112144992Smdodd RET_CG_ERR(err); 113124539Smdodd 114144992Smdodd return CG_OK; 115124539Smdodd} 116144992Smdodd 117124539Smdoddstatic int parse_test_option(struct bpf_test_option *opt, const __u8 *start) 118124539Smdodd{ 119124539Smdodd opt->flags = *start++; 120124539Smdodd 121144992Smdodd if (TEST_OPTION_FLAGS(opt->flags, OPTION_MAX_DELACK_MS)) 122124539Smdodd opt->max_delack_ms = *start++; 123124539Smdodd 124124539Smdodd if (TEST_OPTION_FLAGS(opt->flags, OPTION_RAND)) 125124539Smdodd opt->rand = *start++; 126124539Smdodd 127124539Smdodd return 0; 128124539Smdodd} 129124539Smdodd 130124539Smdoddstatic int load_option(struct bpf_sock_ops *skops, 131144992Smdodd struct bpf_test_option *test_opt, bool from_syn) 132124539Smdodd{ 13348156Sjlemon union { 134144992Smdodd struct tcp_exprm_opt exprm; 135144992Smdodd struct tcp_opt regular; 136144992Smdodd } search_opt; 137124539Smdodd int ret, load_flags = from_syn ? BPF_LOAD_HDR_OPT_TCP_SYN : 0; 138124539Smdodd 13963934Sjlemon if (test_kind == TCPOPT_EXP) { 14063934Sjlemon search_opt.exprm.kind = TCPOPT_EXP; 14163934Sjlemon search_opt.exprm.len = 4; 14263934Sjlemon search_opt.exprm.magic = __bpf_htons(test_magic); 14363934Sjlemon search_opt.exprm.data32 = 0; 14463934Sjlemon ret = bpf_load_hdr_opt(skops, &search_opt.exprm, 14563934Sjlemon sizeof(search_opt.exprm), load_flags); 14663934Sjlemon if (ret < 0) 14763934Sjlemon return ret; 14863934Sjlemon return parse_test_option(test_opt, search_opt.exprm.data); 14963934Sjlemon } else { 15063934Sjlemon search_opt.regular.kind = test_kind; 151103870Salfred search_opt.regular.len = 0; 15248156Sjlemon search_opt.regular.data32 = 0; 153124539Smdodd ret = bpf_load_hdr_opt(skops, &search_opt.regular, 154124539Smdodd sizeof(search_opt.regular), load_flags); 155124539Smdodd if (ret < 0) 156124539Smdodd return ret; 157124539Smdodd return parse_test_option(test_opt, search_opt.regular.data); 158124539Smdodd } 159124539Smdodd} 160124539Smdodd 161124539Smdoddstatic int synack_opt_len(struct bpf_sock_ops *skops) 162124539Smdodd{ 163124539Smdodd struct bpf_test_option test_opt = {}; 164124539Smdodd __u8 optlen; 165124539Smdodd int err; 166124539Smdodd 167124539Smdodd if (!passive_synack_out.flags) 168124539Smdodd return CG_OK; 169124539Smdodd 170124539Smdodd err = load_option(skops, &test_opt, true); 171124539Smdodd 172124539Smdodd /* bpf_test_option is not found */ 173124539Smdodd if (err == -ENOMSG) 174124539Smdodd return CG_OK; 175124539Smdodd 176124539Smdodd if (err) 177124539Smdodd RET_CG_ERR(err); 178124539Smdodd 179124539Smdodd optlen = option_total_len(passive_synack_out.flags); 180124539Smdodd if (optlen) { 181124539Smdodd err = bpf_reserve_hdr_opt(skops, optlen, 0); 182124539Smdodd if (err) 183124539Smdodd RET_CG_ERR(err); 184124539Smdodd } 185124539Smdodd 186124539Smdodd return CG_OK; 187124539Smdodd} 188124539Smdodd 189124539Smdoddstatic int write_synack_opt(struct bpf_sock_ops *skops) 19048156Sjlemon{ 191124539Smdodd struct bpf_test_option opt; 192124539Smdodd 193124539Smdodd if (!passive_synack_out.flags) 194124539Smdodd /* We should not even be called since no header 195124539Smdodd * space has been reserved. 196124539Smdodd */ 197124539Smdodd RET_CG_ERR(0); 198124539Smdodd 199124539Smdodd opt = passive_synack_out; 200124539Smdodd if (skops_want_cookie(skops)) 201124539Smdodd SET_OPTION_FLAGS(opt.flags, OPTION_RESEND); 202124539Smdodd 203124539Smdodd return store_option(skops, &opt); 204124539Smdodd} 205124539Smdodd 206124539Smdoddstatic int syn_opt_len(struct bpf_sock_ops *skops) 207124539Smdodd{ 208124539Smdodd __u8 optlen; 209124539Smdodd int err; 210124539Smdodd 211124539Smdodd if (!active_syn_out.flags) 212124539Smdodd return CG_OK; 213124539Smdodd 214124539Smdodd optlen = option_total_len(active_syn_out.flags); 215124539Smdodd if (optlen) { 216124539Smdodd err = bpf_reserve_hdr_opt(skops, optlen, 0); 217124539Smdodd if (err) 218124539Smdodd RET_CG_ERR(err); 219124539Smdodd } 220124539Smdodd 221124539Smdodd return CG_OK; 222124539Smdodd} 223124539Smdodd 224124539Smdoddstatic int write_syn_opt(struct bpf_sock_ops *skops) 225124539Smdodd{ 226124539Smdodd if (!active_syn_out.flags) 227103870Salfred RET_CG_ERR(0); 22863934Sjlemon 229144991Smdodd return store_option(skops, &active_syn_out); 230124539Smdodd} 231124539Smdodd 232124539Smdoddstatic int fin_opt_len(struct bpf_sock_ops *skops) 23363934Sjlemon{ 23463934Sjlemon struct bpf_test_option *opt; 23563934Sjlemon struct hdr_stg *hdr_stg; 236124539Smdodd __u8 optlen; 237124539Smdodd int err; 238124539Smdodd 23963934Sjlemon if (!skops->sk) 24063934Sjlemon RET_CG_ERR(0); 241124539Smdodd 24263934Sjlemon hdr_stg = bpf_sk_storage_get(&hdr_stg_map, skops->sk, NULL, 0); 24363934Sjlemon if (!hdr_stg) 24463934Sjlemon RET_CG_ERR(0); 24563934Sjlemon 24663934Sjlemon if (hdr_stg->active) 24763934Sjlemon opt = &active_fin_out; 24863934Sjlemon else 24963934Sjlemon opt = &passive_fin_out; 25063934Sjlemon 25163934Sjlemon optlen = option_total_len(opt->flags); 25263934Sjlemon if (optlen) { 25363934Sjlemon err = bpf_reserve_hdr_opt(skops, optlen, 0); 25463934Sjlemon if (err) 25563934Sjlemon RET_CG_ERR(err); 25663934Sjlemon } 25763934Sjlemon 258124539Smdodd return CG_OK; 259103870Salfred} 260124539Smdodd 261124539Smdoddstatic int write_fin_opt(struct bpf_sock_ops *skops) 262124539Smdodd{ 263124539Smdodd struct bpf_test_option *opt; 264124539Smdodd struct hdr_stg *hdr_stg; 265124539Smdodd 266124539Smdodd if (!skops->sk) 267124539Smdodd RET_CG_ERR(0); 268124539Smdodd 269124539Smdodd hdr_stg = bpf_sk_storage_get(&hdr_stg_map, skops->sk, NULL, 0); 270124539Smdodd if (!hdr_stg) 271124539Smdodd RET_CG_ERR(0); 272124539Smdodd 273124539Smdodd if (hdr_stg->active) 274124539Smdodd opt = &active_fin_out; 275124539Smdodd else 276124539Smdodd opt = &passive_fin_out; 277124539Smdodd 278124539Smdodd if (!opt->flags) 279124539Smdodd RET_CG_ERR(0); 280124539Smdodd 281124539Smdodd return store_option(skops, opt); 282124539Smdodd} 283124539Smdodd 284124539Smdoddstatic int resend_in_ack(struct bpf_sock_ops *skops) 285124539Smdodd{ 286124539Smdodd struct hdr_stg *hdr_stg; 287124539Smdodd 288124539Smdodd if (!skops->sk) 289124539Smdodd return -1; 290124539Smdodd 291124539Smdodd hdr_stg = bpf_sk_storage_get(&hdr_stg_map, skops->sk, NULL, 0); 292124539Smdodd if (!hdr_stg) 293124539Smdodd return -1; 294124539Smdodd 295124539Smdodd return !!hdr_stg->resend_syn; 296124539Smdodd} 297124539Smdodd 298124539Smdoddstatic int nodata_opt_len(struct bpf_sock_ops *skops) 299124539Smdodd{ 300124539Smdodd int resend; 301124539Smdodd 302124539Smdodd resend = resend_in_ack(skops); 303124539Smdodd if (resend < 0) 304124539Smdodd RET_CG_ERR(0); 305124539Smdodd 306124539Smdodd if (resend) 307124539Smdodd return syn_opt_len(skops); 308124539Smdodd 309124539Smdodd return CG_OK; 310124539Smdodd} 311124539Smdodd 312124539Smdoddstatic int write_nodata_opt(struct bpf_sock_ops *skops) 313124539Smdodd{ 314124539Smdodd int resend; 315124539Smdodd 316124539Smdodd resend = resend_in_ack(skops); 317124539Smdodd if (resend < 0) 318124539Smdodd RET_CG_ERR(0); 319124539Smdodd 320124539Smdodd if (resend) 321124539Smdodd return write_syn_opt(skops); 322124539Smdodd 323124539Smdodd return CG_OK; 324124539Smdodd} 325124539Smdodd 326124539Smdoddstatic int data_opt_len(struct bpf_sock_ops *skops) 327124539Smdodd{ 328 /* Same as the nodata version. Mostly to show 329 * an example usage on skops->skb_len. 330 */ 331 return nodata_opt_len(skops); 332} 333 334static int write_data_opt(struct bpf_sock_ops *skops) 335{ 336 return write_nodata_opt(skops); 337} 338 339static int current_mss_opt_len(struct bpf_sock_ops *skops) 340{ 341 /* Reserve maximum that may be needed */ 342 int err; 343 344 err = bpf_reserve_hdr_opt(skops, option_total_len(OPTION_MASK), 0); 345 if (err) 346 RET_CG_ERR(err); 347 348 return CG_OK; 349} 350 351static int handle_hdr_opt_len(struct bpf_sock_ops *skops) 352{ 353 __u8 tcp_flags = skops_tcp_flags(skops); 354 355 if ((tcp_flags & TCPHDR_SYNACK) == TCPHDR_SYNACK) 356 return synack_opt_len(skops); 357 358 if (tcp_flags & TCPHDR_SYN) 359 return syn_opt_len(skops); 360 361 if (tcp_flags & TCPHDR_FIN) 362 return fin_opt_len(skops); 363 364 if (skops_current_mss(skops)) 365 /* The kernel is calculating the MSS */ 366 return current_mss_opt_len(skops); 367 368 if (skops->skb_len) 369 return data_opt_len(skops); 370 371 return nodata_opt_len(skops); 372} 373 374static int handle_write_hdr_opt(struct bpf_sock_ops *skops) 375{ 376 __u8 tcp_flags = skops_tcp_flags(skops); 377 struct tcphdr *th; 378 379 if ((tcp_flags & TCPHDR_SYNACK) == TCPHDR_SYNACK) 380 return write_synack_opt(skops); 381 382 if (tcp_flags & TCPHDR_SYN) 383 return write_syn_opt(skops); 384 385 if (tcp_flags & TCPHDR_FIN) 386 return write_fin_opt(skops); 387 388 th = skops->skb_data; 389 if (th + 1 > skops->skb_data_end) 390 RET_CG_ERR(0); 391 392 if (skops->skb_len > tcp_hdrlen(th)) 393 return write_data_opt(skops); 394 395 return write_nodata_opt(skops); 396} 397 398static int set_delack_max(struct bpf_sock_ops *skops, __u8 max_delack_ms) 399{ 400 __u32 max_delack_us = max_delack_ms * 1000; 401 402 return bpf_setsockopt(skops, SOL_TCP, TCP_BPF_DELACK_MAX, 403 &max_delack_us, sizeof(max_delack_us)); 404} 405 406static int set_rto_min(struct bpf_sock_ops *skops, __u8 peer_max_delack_ms) 407{ 408 __u32 min_rto_us = peer_max_delack_ms * 1000; 409 410 return bpf_setsockopt(skops, SOL_TCP, TCP_BPF_RTO_MIN, &min_rto_us, 411 sizeof(min_rto_us)); 412} 413 414static int handle_active_estab(struct bpf_sock_ops *skops) 415{ 416 struct hdr_stg init_stg = { 417 .active = true, 418 }; 419 int err; 420 421 err = load_option(skops, &active_estab_in, false); 422 if (err && err != -ENOMSG) 423 RET_CG_ERR(err); 424 425 init_stg.resend_syn = TEST_OPTION_FLAGS(active_estab_in.flags, 426 OPTION_RESEND); 427 if (!skops->sk || !bpf_sk_storage_get(&hdr_stg_map, skops->sk, 428 &init_stg, 429 BPF_SK_STORAGE_GET_F_CREATE)) 430 RET_CG_ERR(0); 431 432 if (init_stg.resend_syn) 433 /* Don't clear the write_hdr cb now because 434 * the ACK may get lost and retransmit may 435 * be needed. 436 * 437 * PARSE_ALL_HDR cb flag is set to learn if this 438 * resend_syn option has received by the peer. 439 * 440 * The header option will be resent until a valid 441 * packet is received at handle_parse_hdr() 442 * and all hdr cb flags will be cleared in 443 * handle_parse_hdr(). 444 */ 445 set_parse_all_hdr_cb_flags(skops); 446 else if (!active_fin_out.flags) 447 /* No options will be written from now */ 448 clear_hdr_cb_flags(skops); 449 450 if (active_syn_out.max_delack_ms) { 451 err = set_delack_max(skops, active_syn_out.max_delack_ms); 452 if (err) 453 RET_CG_ERR(err); 454 } 455 456 if (active_estab_in.max_delack_ms) { 457 err = set_rto_min(skops, active_estab_in.max_delack_ms); 458 if (err) 459 RET_CG_ERR(err); 460 } 461 462 return CG_OK; 463} 464 465static int handle_passive_estab(struct bpf_sock_ops *skops) 466{ 467 struct hdr_stg init_stg = {}; 468 struct tcphdr *th; 469 int err; 470 471 inherit_cb_flags = skops->bpf_sock_ops_cb_flags; 472 473 err = load_option(skops, &passive_estab_in, true); 474 if (err == -ENOENT) { 475 /* saved_syn is not found. It was in syncookie mode. 476 * We have asked the active side to resend the options 477 * in ACK, so try to find the bpf_test_option from ACK now. 478 */ 479 err = load_option(skops, &passive_estab_in, false); 480 init_stg.syncookie = true; 481 } 482 483 /* ENOMSG: The bpf_test_option is not found which is fine. 484 * Bail out now for all other errors. 485 */ 486 if (err && err != -ENOMSG) 487 RET_CG_ERR(err); 488 489 th = skops->skb_data; 490 if (th + 1 > skops->skb_data_end) 491 RET_CG_ERR(0); 492 493 if (th->syn) { 494 /* Fastopen */ 495 496 /* Cannot clear cb_flags to stop write_hdr cb. 497 * synack is not sent yet for fast open. 498 * Even it was, the synack may need to be retransmitted. 499 * 500 * PARSE_ALL_HDR cb flag is set to learn 501 * if synack has reached the peer. 502 * All cb_flags will be cleared in handle_parse_hdr(). 503 */ 504 set_parse_all_hdr_cb_flags(skops); 505 init_stg.fastopen = true; 506 } else if (!passive_fin_out.flags) { 507 /* No options will be written from now */ 508 clear_hdr_cb_flags(skops); 509 } 510 511 if (!skops->sk || 512 !bpf_sk_storage_get(&hdr_stg_map, skops->sk, &init_stg, 513 BPF_SK_STORAGE_GET_F_CREATE)) 514 RET_CG_ERR(0); 515 516 if (passive_synack_out.max_delack_ms) { 517 err = set_delack_max(skops, passive_synack_out.max_delack_ms); 518 if (err) 519 RET_CG_ERR(err); 520 } 521 522 if (passive_estab_in.max_delack_ms) { 523 err = set_rto_min(skops, passive_estab_in.max_delack_ms); 524 if (err) 525 RET_CG_ERR(err); 526 } 527 528 return CG_OK; 529} 530 531static int handle_parse_hdr(struct bpf_sock_ops *skops) 532{ 533 struct hdr_stg *hdr_stg; 534 struct tcphdr *th; 535 536 if (!skops->sk) 537 RET_CG_ERR(0); 538 539 th = skops->skb_data; 540 if (th + 1 > skops->skb_data_end) 541 RET_CG_ERR(0); 542 543 hdr_stg = bpf_sk_storage_get(&hdr_stg_map, skops->sk, NULL, 0); 544 if (!hdr_stg) 545 RET_CG_ERR(0); 546 547 if (hdr_stg->resend_syn || hdr_stg->fastopen) 548 /* The PARSE_ALL_HDR cb flag was turned on 549 * to ensure that the previously written 550 * options have reached the peer. 551 * Those previously written option includes: 552 * - Active side: resend_syn in ACK during syncookie 553 * or 554 * - Passive side: SYNACK during fastopen 555 * 556 * A valid packet has been received here after 557 * the 3WHS, so the PARSE_ALL_HDR cb flag 558 * can be cleared now. 559 */ 560 clear_parse_all_hdr_cb_flags(skops); 561 562 if (hdr_stg->resend_syn && !active_fin_out.flags) 563 /* Active side resent the syn option in ACK 564 * because the server was in syncookie mode. 565 * A valid packet has been received, so 566 * clear header cb flags if there is no 567 * more option to send. 568 */ 569 clear_hdr_cb_flags(skops); 570 571 if (hdr_stg->fastopen && !passive_fin_out.flags) 572 /* Passive side was in fastopen. 573 * A valid packet has been received, so 574 * the SYNACK has reached the peer. 575 * Clear header cb flags if there is no more 576 * option to send. 577 */ 578 clear_hdr_cb_flags(skops); 579 580 if (th->fin) { 581 struct bpf_test_option *fin_opt; 582 int err; 583 584 if (hdr_stg->active) 585 fin_opt = &active_fin_in; 586 else 587 fin_opt = &passive_fin_in; 588 589 err = load_option(skops, fin_opt, false); 590 if (err && err != -ENOMSG) 591 RET_CG_ERR(err); 592 } 593 594 return CG_OK; 595} 596 597SEC("sockops") 598int estab(struct bpf_sock_ops *skops) 599{ 600 int true_val = 1; 601 602 switch (skops->op) { 603 case BPF_SOCK_OPS_TCP_LISTEN_CB: 604 bpf_setsockopt(skops, SOL_TCP, TCP_SAVE_SYN, 605 &true_val, sizeof(true_val)); 606 set_hdr_cb_flags(skops, BPF_SOCK_OPS_STATE_CB_FLAG); 607 break; 608 case BPF_SOCK_OPS_TCP_CONNECT_CB: 609 set_hdr_cb_flags(skops, 0); 610 break; 611 case BPF_SOCK_OPS_PARSE_HDR_OPT_CB: 612 return handle_parse_hdr(skops); 613 case BPF_SOCK_OPS_HDR_OPT_LEN_CB: 614 return handle_hdr_opt_len(skops); 615 case BPF_SOCK_OPS_WRITE_HDR_OPT_CB: 616 return handle_write_hdr_opt(skops); 617 case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: 618 return handle_passive_estab(skops); 619 case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: 620 return handle_active_estab(skops); 621 } 622 623 return CG_OK; 624} 625 626char _license[] SEC("license") = "GPL"; 627