| // SPDX-License-Identifier: GPL-2.0 |
| /* Copyright (C) B.A.T.M.A.N. contributors: |
| * |
| * Marek Lindner |
| */ |
| |
| #include "gateway_common.h" |
| #include "main.h" |
| |
| #include <linux/atomic.h> |
| #include <linux/byteorder/generic.h> |
| #include <linux/stddef.h> |
| #include <linux/types.h> |
| #include <uapi/linux/batadv_packet.h> |
| #include <uapi/linux/batman_adv.h> |
| |
| #include "gateway_client.h" |
| #include "tvlv.h" |
| |
| /** |
| * batadv_gw_tvlv_container_update() - update the gw tvlv container after |
| * gateway setting change |
| * @bat_priv: the bat priv with all the soft interface information |
| */ |
| void batadv_gw_tvlv_container_update(struct batadv_priv *bat_priv) |
| { |
| struct batadv_tvlv_gateway_data gw; |
| u32 down, up; |
| char gw_mode; |
| |
| gw_mode = atomic_read(&bat_priv->gw.mode); |
| |
| switch (gw_mode) { |
| case BATADV_GW_MODE_OFF: |
| case BATADV_GW_MODE_CLIENT: |
| batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_GW, 1); |
| break; |
| case BATADV_GW_MODE_SERVER: |
| down = atomic_read(&bat_priv->gw.bandwidth_down); |
| up = atomic_read(&bat_priv->gw.bandwidth_up); |
| gw.bandwidth_down = htonl(down); |
| gw.bandwidth_up = htonl(up); |
| batadv_tvlv_container_register(bat_priv, BATADV_TVLV_GW, 1, |
| &gw, sizeof(gw)); |
| break; |
| } |
| } |
| |
| /** |
| * batadv_gw_tvlv_ogm_handler_v1() - process incoming gateway tvlv container |
| * @bat_priv: the bat priv with all the soft interface information |
| * @orig: the orig_node of the ogm |
| * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags) |
| * @tvlv_value: tvlv buffer containing the gateway data |
| * @tvlv_value_len: tvlv buffer length |
| */ |
| static void batadv_gw_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, |
| struct batadv_orig_node *orig, |
| u8 flags, |
| void *tvlv_value, u16 tvlv_value_len) |
| { |
| struct batadv_tvlv_gateway_data gateway, *gateway_ptr; |
| |
| /* only fetch the tvlv value if the handler wasn't called via the |
| * CIFNOTFND flag and if there is data to fetch |
| */ |
| if (flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND || |
| tvlv_value_len < sizeof(gateway)) { |
| gateway.bandwidth_down = 0; |
| gateway.bandwidth_up = 0; |
| } else { |
| gateway_ptr = tvlv_value; |
| gateway.bandwidth_down = gateway_ptr->bandwidth_down; |
| gateway.bandwidth_up = gateway_ptr->bandwidth_up; |
| if (gateway.bandwidth_down == 0 || |
| gateway.bandwidth_up == 0) { |
| gateway.bandwidth_down = 0; |
| gateway.bandwidth_up = 0; |
| } |
| } |
| |
| batadv_gw_node_update(bat_priv, orig, &gateway); |
| |
| /* restart gateway selection */ |
| if (gateway.bandwidth_down != 0 && |
| atomic_read(&bat_priv->gw.mode) == BATADV_GW_MODE_CLIENT) |
| batadv_gw_check_election(bat_priv, orig); |
| } |
| |
| /** |
| * batadv_gw_init() - initialise the gateway handling internals |
| * @bat_priv: the bat priv with all the soft interface information |
| */ |
| void batadv_gw_init(struct batadv_priv *bat_priv) |
| { |
| if (bat_priv->algo_ops->gw.init_sel_class) |
| bat_priv->algo_ops->gw.init_sel_class(bat_priv); |
| else |
| atomic_set(&bat_priv->gw.sel_class, 1); |
| |
| batadv_tvlv_handler_register(bat_priv, batadv_gw_tvlv_ogm_handler_v1, |
| NULL, NULL, BATADV_TVLV_GW, 1, |
| BATADV_TVLV_HANDLER_OGM_CIFNOTFND); |
| } |
| |
| /** |
| * batadv_gw_free() - free the gateway handling internals |
| * @bat_priv: the bat priv with all the soft interface information |
| */ |
| void batadv_gw_free(struct batadv_priv *bat_priv) |
| { |
| batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_GW, 1); |
| batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_GW, 1); |
| } |