/* SPDX-License-Identifier: (BSD-2-Clause OR GPL-2.0-or-later)
 *
 * vim:set noexpandtab shiftwidth=8 softtabstop=8 fileencoding=utf-8:
 *
 * Layer 2 network upstream uapi access library
 */

/** @file net_upstream_api.h */

#include <stdint.h>

#include <linux/if_ether.h>

/** Open a net_us device
 *
 * The first available device is picked and opened. A file descriptor is returned
 * that's suitable for the other net_us_* APIs.
 *
 * Additionally, a net_upstream%%d proxy network interface is created automatically
 * where  %%d corresponds to the minor number of the open device. The network
 * interface  may be configured and used like a normal interface but it's rather
 * useless  before a master device is linked net_us_set_master(), as all packets
 * are being dropped.
 *
 * @see net_us_close()
 *
 * @return file descriptor to the device
 */
int net_us_open(void);

/** Close an open net_us device
 *
 * The network interface associated with the device is torn down as well.
 *
 * @param fd The open net_us device
 */
void net_us_close(int fd);

/** Get the interface index of the net_upstream interface
 *
 * Because you cannot reliably predict the name of the net_upstream interface
 * that is created along with this net_us device you can retrieve its interface
 * index with this function.
 *
 * You can pass it then to @a if_indextoname() to access the name.
 *
 * @param fd The open net_us device
 *
 * @return The interface index (> 0) or -1 on error.
 */
int net_us_get_ifindex(int fd);

/** Link a master interface
 *
 * The master interface is central to net_upstream operation
 * - Packets sent through an net_upstream interface are forwarded to the master
 * - Packets received on the master interface are forwarded to the net_upstream interface
 *
 * So, unless tx actions are configured, a net_upstream interface is a simple proxy
 * interfface. However, it can be created and configured independently, e.g. before
 * the master interface even exists.
 *
 * Only one master can be linked. The function returns and sets errno if
 * there is already one master linked.
 *
 * @see net_us_clear_master()
 *
 * @param fd The open net_us device
 * @param ifindex The interface index of the master
 *
 * @return 0 on success, -1 otherwise
 */
int net_us_set_master(int fd, int ifindex);

/** Unlink a master interface
 *
 * Break the connection to a master interface that was previously linked with
 * net_us_set_master(). Afterwards the net_upstream interface will drop transmitted
 * packets and will not receive any packets.
 *
 * It is an error if the function is called on a unlinked net_us device.
 *
 * @param fd The open net_us device
 *
 * @return 0 on success, -1 otherwise
 */
int net_us_clear_master(int fd);

/** Add a vlanprio map tx action.
 *
 * The vlanprio map tx action sets the vlanprio bits in the VLAN header of
 * transmitted packets, before the packets are forwaded to the linked master
 * interface.
 *
 * The vlanprio bits are set according to the map that's configured here.
 * The map maps skb->priority to the corresponding PCP value..
 *
 * You can add different maps for different vlan ranges. E.g. vlan 7 can use
 * a different map that vlans 8-10.
 *
 * Keep in mind that in the VLAN context, 0 and 1 are swapped. 0/Best Effort has
 * a higher priority than 1/Background. Otherwise a higher PCP value indicates
 * higher priority.
 *
 * @see net_us_tx_clear_all()
 *
 * @param fd The open net_us device
 * @param vlan_start Start of the vlan range
 * @param vlan_end End (inclusive) of the vlan range
 * @param map An array of PCP values
 * @param map_len The length of the PCP value arraz.
 *
 * @return 0 on success, -1 otherwise
 */
int net_us_tx_add_vlanprio_map(int fd, int vlan_start, int vlan_end, uint8_t *map, int map_len);

/** Clear all tx actions
 *
 * This clears every tx action that was previously configured with net_us_tx_add_*.
 * Afterwards, every packet is directly forwarded to the master interface without
 * any tx action applied. Consider seting the net_upstream interface down before
 * if that's a problem.
 *
 * @param fd The open net_us device
 *
 * @return 0 on success, -1 otherwise
 */
int net_us_tx_clear_all(int fd);


/** Add mac pass-through rx action (source)
 *
 * Install a source-based mac address filter. Packets matching the mac address
 * in their source address will pass through the IP stack, i.e. will not
 * be received on the net_upstream interface.
 *
 * @see net_us_rx_add_mac_passthrough_dest() for a destination-based filter.
 * @see net_us_tx_clear_all() for clearing rx actions.
 *
 * @param fd The open net_us device
 * @param mac The Ethernet address to match
 *
 * @return 0 on success, -1 otherwise
 */
int net_us_rx_add_mac_passthrough_src(int fd, uint8_t mac[ETH_ALEN]);


/** Add mac pass-through rx action (source)
 *
 * Install a source-based mac address filter. Packets matching the mac address
 * in their source address will pass through the IP stack, i.e. will not
 * be received on the net_upstream interface.
 *
 * @see net_us_rx_add_mac_passthrough_src() for a source-based filter.
 * @see net_us_tx_clear_all() for clearing rx actions.
 *
 * @param fd The open net_us device
 * @param mac The Ethernet address to match
 *
 * @return 0 on success, -1 otherwise
 */int net_us_rx_add_mac_passthrough_dest(int fd, uint8_t mac[ETH_ALEN]);

/** Clear all rx actions
 *
 * This clears every tx action that was previously configured with net_us_rx_add_*.
 * Afterwards, every packet is directly forwarded to the master interface without
 * any rx action applied. Consider seting the net_upstream interface down before
 * if that's a problem.
 *
 * @param fd The open net_us device
 *
 * @return 0 on success, -1 otherwise
 */
int net_us_rx_clear_all(int fd);