162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright (C) B.A.T.M.A.N. contributors:
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Marek Lindner
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include "gateway_common.h"
862306a36Sopenharmony_ci#include "main.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/atomic.h>
1162306a36Sopenharmony_ci#include <linux/byteorder/generic.h>
1262306a36Sopenharmony_ci#include <linux/stddef.h>
1362306a36Sopenharmony_ci#include <linux/types.h>
1462306a36Sopenharmony_ci#include <uapi/linux/batadv_packet.h>
1562306a36Sopenharmony_ci#include <uapi/linux/batman_adv.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "gateway_client.h"
1862306a36Sopenharmony_ci#include "tvlv.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/**
2162306a36Sopenharmony_ci * batadv_gw_tvlv_container_update() - update the gw tvlv container after
2262306a36Sopenharmony_ci *  gateway setting change
2362306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
2462306a36Sopenharmony_ci */
2562306a36Sopenharmony_civoid batadv_gw_tvlv_container_update(struct batadv_priv *bat_priv)
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci	struct batadv_tvlv_gateway_data gw;
2862306a36Sopenharmony_ci	u32 down, up;
2962306a36Sopenharmony_ci	char gw_mode;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	gw_mode = atomic_read(&bat_priv->gw.mode);
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	switch (gw_mode) {
3462306a36Sopenharmony_ci	case BATADV_GW_MODE_OFF:
3562306a36Sopenharmony_ci	case BATADV_GW_MODE_CLIENT:
3662306a36Sopenharmony_ci		batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_GW, 1);
3762306a36Sopenharmony_ci		break;
3862306a36Sopenharmony_ci	case BATADV_GW_MODE_SERVER:
3962306a36Sopenharmony_ci		down = atomic_read(&bat_priv->gw.bandwidth_down);
4062306a36Sopenharmony_ci		up = atomic_read(&bat_priv->gw.bandwidth_up);
4162306a36Sopenharmony_ci		gw.bandwidth_down = htonl(down);
4262306a36Sopenharmony_ci		gw.bandwidth_up = htonl(up);
4362306a36Sopenharmony_ci		batadv_tvlv_container_register(bat_priv, BATADV_TVLV_GW, 1,
4462306a36Sopenharmony_ci					       &gw, sizeof(gw));
4562306a36Sopenharmony_ci		break;
4662306a36Sopenharmony_ci	}
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci/**
5062306a36Sopenharmony_ci * batadv_gw_tvlv_ogm_handler_v1() - process incoming gateway tvlv container
5162306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
5262306a36Sopenharmony_ci * @orig: the orig_node of the ogm
5362306a36Sopenharmony_ci * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags)
5462306a36Sopenharmony_ci * @tvlv_value: tvlv buffer containing the gateway data
5562306a36Sopenharmony_ci * @tvlv_value_len: tvlv buffer length
5662306a36Sopenharmony_ci */
5762306a36Sopenharmony_cistatic void batadv_gw_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
5862306a36Sopenharmony_ci					  struct batadv_orig_node *orig,
5962306a36Sopenharmony_ci					  u8 flags,
6062306a36Sopenharmony_ci					  void *tvlv_value, u16 tvlv_value_len)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	struct batadv_tvlv_gateway_data gateway, *gateway_ptr;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	/* only fetch the tvlv value if the handler wasn't called via the
6562306a36Sopenharmony_ci	 * CIFNOTFND flag and if there is data to fetch
6662306a36Sopenharmony_ci	 */
6762306a36Sopenharmony_ci	if (flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND ||
6862306a36Sopenharmony_ci	    tvlv_value_len < sizeof(gateway)) {
6962306a36Sopenharmony_ci		gateway.bandwidth_down = 0;
7062306a36Sopenharmony_ci		gateway.bandwidth_up = 0;
7162306a36Sopenharmony_ci	} else {
7262306a36Sopenharmony_ci		gateway_ptr = tvlv_value;
7362306a36Sopenharmony_ci		gateway.bandwidth_down = gateway_ptr->bandwidth_down;
7462306a36Sopenharmony_ci		gateway.bandwidth_up = gateway_ptr->bandwidth_up;
7562306a36Sopenharmony_ci		if (gateway.bandwidth_down == 0 ||
7662306a36Sopenharmony_ci		    gateway.bandwidth_up == 0) {
7762306a36Sopenharmony_ci			gateway.bandwidth_down = 0;
7862306a36Sopenharmony_ci			gateway.bandwidth_up = 0;
7962306a36Sopenharmony_ci		}
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	batadv_gw_node_update(bat_priv, orig, &gateway);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	/* restart gateway selection */
8562306a36Sopenharmony_ci	if (gateway.bandwidth_down != 0 &&
8662306a36Sopenharmony_ci	    atomic_read(&bat_priv->gw.mode) == BATADV_GW_MODE_CLIENT)
8762306a36Sopenharmony_ci		batadv_gw_check_election(bat_priv, orig);
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci/**
9162306a36Sopenharmony_ci * batadv_gw_init() - initialise the gateway handling internals
9262306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
9362306a36Sopenharmony_ci */
9462306a36Sopenharmony_civoid batadv_gw_init(struct batadv_priv *bat_priv)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	if (bat_priv->algo_ops->gw.init_sel_class)
9762306a36Sopenharmony_ci		bat_priv->algo_ops->gw.init_sel_class(bat_priv);
9862306a36Sopenharmony_ci	else
9962306a36Sopenharmony_ci		atomic_set(&bat_priv->gw.sel_class, 1);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	batadv_tvlv_handler_register(bat_priv, batadv_gw_tvlv_ogm_handler_v1,
10262306a36Sopenharmony_ci				     NULL, NULL, BATADV_TVLV_GW, 1,
10362306a36Sopenharmony_ci				     BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci/**
10762306a36Sopenharmony_ci * batadv_gw_free() - free the gateway handling internals
10862306a36Sopenharmony_ci * @bat_priv: the bat priv with all the soft interface information
10962306a36Sopenharmony_ci */
11062306a36Sopenharmony_civoid batadv_gw_free(struct batadv_priv *bat_priv)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_GW, 1);
11362306a36Sopenharmony_ci	batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_GW, 1);
11462306a36Sopenharmony_ci}
115