/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <linux/if.h>
#include <linux/if_ether.h>
#include <linux/in.h>
#include <linux/in6.h>

// Common definitions for BPF code in the tethering mainline module.
// These definitions are available to:
// - The BPF programs in Tethering/bpf_progs/
// - JNI code that depends on the bpf_tethering_headers library.

#define BPF_TETHER_ERRORS    \
    ERR(INVALID_IP_VERSION)  \
    ERR(LOW_TTL)             \
    ERR(INVALID_TCP_HEADER)  \
    ERR(TCP_CONTROL_PACKET)  \
    ERR(NON_GLOBAL_SRC)      \
    ERR(NON_GLOBAL_DST)      \
    ERR(LOCAL_SRC_DST)       \
    ERR(NO_STATS_ENTRY)      \
    ERR(NO_LIMIT_ENTRY)      \
    ERR(BELOW_IPV4_MTU)      \
    ERR(BELOW_IPV6_MTU)      \
    ERR(LIMIT_REACHED)       \
    ERR(CHANGE_HEAD_FAILED)  \
    ERR(TOO_SHORT)           \
    ERR(HAS_IP_OPTIONS)      \
    ERR(IS_IP_FRAG)          \
    ERR(CHECKSUM)            \
    ERR(NON_TCP_UDP)         \
    ERR(NON_TCP)             \
    ERR(SHORT_L4_HEADER)     \
    ERR(SHORT_TCP_HEADER)    \
    ERR(SHORT_UDP_HEADER)    \
    ERR(UDP_CSUM_ZERO)       \
    ERR(TRUNCATED_IPV4)      \
    ERR(_MAX)

#define ERR(x) BPF_TETHER_ERR_ ##x,
enum {
    BPF_TETHER_ERRORS
};
#undef ERR

#define ERR(x) #x,
static const char *bpf_tether_errors[] = {
    BPF_TETHER_ERRORS
};
#undef ERR

// This header file is shared by eBPF kernel programs (C) and netd (C++) and
// some of the maps are also accessed directly from Java mainline module code.
//
// Hence: explicitly pad all relevant structures and assert that their size
// is the sum of the sizes of their fields.
#define STRUCT_SIZE(name, size) _Static_assert(sizeof(name) == (size), "Incorrect struct size.")


#define BPF_PATH_TETHER BPF_PATH "tethering/"

#define TETHER_STATS_MAP_PATH BPF_PATH_TETHER "map_offload_tether_stats_map"

typedef uint32_t TetherStatsKey;  // upstream ifindex

typedef struct {
    uint64_t rxPackets;
    uint64_t rxBytes;
    uint64_t rxErrors;
    uint64_t txPackets;
    uint64_t txBytes;
    uint64_t txErrors;
} TetherStatsValue;
STRUCT_SIZE(TetherStatsValue, 6 * 8);  // 48

#define TETHER_LIMIT_MAP_PATH BPF_PATH_TETHER "map_offload_tether_limit_map"

typedef uint32_t TetherLimitKey;    // upstream ifindex
typedef uint64_t TetherLimitValue;  // in bytes

#define TETHER_DOWNSTREAM6_TC_PROG_RAWIP_NAME "prog_offload_schedcls_tether_downstream6_rawip"
#define TETHER_DOWNSTREAM6_TC_PROG_ETHER_NAME "prog_offload_schedcls_tether_downstream6_ether"

#define TETHER_DOWNSTREAM6_TC_PROG_RAWIP_PATH BPF_PATH_TETHER TETHER_DOWNSTREAM6_TC_PROG_RAWIP_NAME
#define TETHER_DOWNSTREAM6_TC_PROG_ETHER_PATH BPF_PATH_TETHER TETHER_DOWNSTREAM6_TC_PROG_ETHER_NAME

#define TETHER_DOWNSTREAM6_MAP_PATH BPF_PATH_TETHER "map_offload_tether_downstream6_map"

// For now tethering offload only needs to support downstreams that use 6-byte MAC addresses,
// because all downstream types that are currently supported (WiFi, USB, Bluetooth and
// Ethernet) have 6-byte MAC addresses.

typedef struct {
    uint32_t iif;              // The input interface index
    uint8_t dstMac[ETH_ALEN];  // destination ethernet mac address (zeroed iff rawip ingress)
    uint8_t zero[2];           // zero pad for 8 byte alignment
    struct in6_addr neigh6;    // The destination IPv6 address
} TetherDownstream6Key;
STRUCT_SIZE(TetherDownstream6Key, 4 + 6 + 2 + 16);  // 28

typedef struct {
    uint32_t oif;             // The output interface to redirect to
    struct ethhdr macHeader;  // includes dst/src mac and ethertype (zeroed iff rawip egress)
    uint16_t pmtu;            // The maximum L3 output path/route mtu
} Tether6Value;
STRUCT_SIZE(Tether6Value, 4 + 14 + 2);  // 20

#define TETHER_DOWNSTREAM64_MAP_PATH BPF_PATH_TETHER "map_offload_tether_downstream64_map"

typedef struct {
    uint32_t iif;              // The input interface index
    uint8_t dstMac[ETH_ALEN];  // destination ethernet mac address (zeroed iff rawip ingress)
    uint16_t l4Proto;          // IPPROTO_TCP/UDP/...
    struct in6_addr src6;      // source &
    struct in6_addr dst6;      // destination IPv6 addresses
    __be16 srcPort;            // source &
    __be16 dstPort;            // destination tcp/udp/... ports
} TetherDownstream64Key;
STRUCT_SIZE(TetherDownstream64Key, 4 + 6 + 2 + 16 + 16 + 2 + 2);  // 48

typedef struct {
    uint32_t oif;             // The output interface to redirect to
    struct ethhdr macHeader;  // includes dst/src mac and ethertype (zeroed iff rawip egress)
    uint16_t pmtu;            // The maximum L3 output path/route mtu
    struct in_addr src4;      // source &
    struct in_addr dst4;      // destination IPv4 addresses
    __be16 srcPort;           // source &
    __be16 outPort;           // destination tcp/udp/... ports
    uint64_t lastUsed;        // Kernel updates on each use with bpf_ktime_get_boot_ns()
} TetherDownstream64Value;
STRUCT_SIZE(TetherDownstream64Value, 4 + 14 + 2 + 4 + 4 + 2 + 2 + 8);  // 40

#define TETHER_UPSTREAM6_TC_PROG_RAWIP_NAME "prog_offload_schedcls_tether_upstream6_rawip"
#define TETHER_UPSTREAM6_TC_PROG_ETHER_NAME "prog_offload_schedcls_tether_upstream6_ether"

#define TETHER_UPSTREAM6_TC_PROG_RAWIP_PATH BPF_PATH_TETHER TETHER_UPSTREAM6_TC_PROG_RAWIP_NAME
#define TETHER_UPSTREAM6_TC_PROG_ETHER_PATH BPF_PATH_TETHER TETHER_UPSTREAM6_TC_PROG_ETHER_NAME

#define TETHER_UPSTREAM6_MAP_PATH BPF_PATH_TETHER "map_offload_tether_upstream6_map"

typedef struct {
    uint32_t iif;              // The input interface index
    uint8_t dstMac[ETH_ALEN];  // destination ethernet mac address (zeroed iff rawip ingress)
    uint8_t zero[2];           // zero pad for 8 byte alignment
                               // TODO: extend this to include src ip /64 subnet
} TetherUpstream6Key;
STRUCT_SIZE(TetherUpstream6Key, 12);

#define TETHER_DOWNSTREAM4_TC_PROG_RAWIP_NAME "prog_offload_schedcls_tether_downstream4_rawip"
#define TETHER_DOWNSTREAM4_TC_PROG_ETHER_NAME "prog_offload_schedcls_tether_downstream4_ether"

#define TETHER_DOWNSTREAM4_TC_PROG_RAWIP_PATH BPF_PATH_TETHER TETHER_DOWNSTREAM4_TC_PROG_RAWIP_NAME
#define TETHER_DOWNSTREAM4_TC_PROG_ETHER_PATH BPF_PATH_TETHER TETHER_DOWNSTREAM4_TC_PROG_ETHER_NAME

#define TETHER_DOWNSTREAM4_MAP_PATH BPF_PATH_TETHER "map_offload_tether_downstream4_map"


#define TETHER_UPSTREAM4_TC_PROG_RAWIP_NAME "prog_offload_schedcls_tether_upstream4_rawip"
#define TETHER_UPSTREAM4_TC_PROG_ETHER_NAME "prog_offload_schedcls_tether_upstream4_ether"

#define TETHER_UPSTREAM4_TC_PROG_RAWIP_PATH BPF_PATH_TETHER TETHER_UPSTREAM4_TC_PROG_RAWIP_NAME
#define TETHER_UPSTREAM4_TC_PROG_ETHER_PATH BPF_PATH_TETHER TETHER_UPSTREAM4_TC_PROG_ETHER_NAME

#define TETHER_UPSTREAM4_MAP_PATH BPF_PATH_TETHER "map_offload_tether_upstream4_map"

typedef struct {
    uint32_t iif;              // The input interface index
    uint8_t dstMac[ETH_ALEN];  // destination ethernet mac address (zeroed iff rawip ingress)
    uint16_t l4Proto;          // IPPROTO_TCP/UDP/...
    struct in_addr src4;       // source &
    struct in_addr dst4;       // destination IPv4 addresses
    __be16 srcPort;            // source &
    __be16 dstPort;            // destination TCP/UDP/... ports
} Tether4Key;
STRUCT_SIZE(Tether4Key, 4 + 6 + 2 + 4 + 4 + 2 + 2);  // 24

typedef struct {
    uint32_t oif;             // The output interface to redirect to
    struct ethhdr macHeader;  // includes dst/src mac and ethertype (zeroed iff rawip egress)
    uint16_t pmtu;            // Maximum L3 output path/route mtu
    struct in6_addr src46;    // source &                 (always IPv4 mapped for downstream)
    struct in6_addr dst46;    // destination IP addresses (may be IPv4 mapped or IPv6 for upstream)
    __be16 srcPort;           // source &
    __be16 dstPort;           // destination tcp/udp/... ports
    uint64_t last_used;       // Kernel updates on each use with bpf_ktime_get_boot_ns()
} Tether4Value;
STRUCT_SIZE(Tether4Value, 4 + 14 + 2 + 16 + 16 + 2 + 2 + 8);  // 64

#define TETHER_DOWNSTREAM_XDP_PROG_RAWIP_NAME "prog_offload_xdp_tether_downstream_rawip"
#define TETHER_DOWNSTREAM_XDP_PROG_ETHER_NAME "prog_offload_xdp_tether_downstream_ether"

#define TETHER_DOWNSTREAM_XDP_PROG_RAWIP_PATH BPF_PATH_TETHER TETHER_DOWNSTREAM_XDP_PROG_RAWIP_NAME
#define TETHER_DOWNSTREAM_XDP_PROG_ETHER_PATH BPF_PATH_TETHER TETHER_DOWNSTREAM_XDP_PROG_ETHER_NAME

#define TETHER_UPSTREAM_XDP_PROG_RAWIP_NAME "prog_offload_xdp_tether_upstream_rawip"
#define TETHER_UPSTREAM_XDP_PROG_ETHER_NAME "prog_offload_xdp_tether_upstream_ether"

#define TETHER_UPSTREAM_XDP_PROG_RAWIP_PATH BPF_PATH_TETHER TETHER_UPSTREAM_XDP_PROG_RAWIP_NAME
#define TETHER_UPSTREAM_XDP_PROG_ETHER_PATH BPF_PATH_TETHER TETHER_UPSTREAM_XDP_PROG_ETHER_NAME

#undef STRUCT_SIZE