162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * drivers/net/team/team_mode_broadcast.c - Broadcast mode for team
462306a36Sopenharmony_ci * Copyright (c) 2012 Jiri Pirko <jpirko@redhat.com>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/kernel.h>
862306a36Sopenharmony_ci#include <linux/types.h>
962306a36Sopenharmony_ci#include <linux/module.h>
1062306a36Sopenharmony_ci#include <linux/init.h>
1162306a36Sopenharmony_ci#include <linux/netdevice.h>
1262306a36Sopenharmony_ci#include <linux/if_team.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistatic bool bc_transmit(struct team *team, struct sk_buff *skb)
1562306a36Sopenharmony_ci{
1662306a36Sopenharmony_ci	struct team_port *cur;
1762306a36Sopenharmony_ci	struct team_port *last = NULL;
1862306a36Sopenharmony_ci	struct sk_buff *skb2;
1962306a36Sopenharmony_ci	bool ret;
2062306a36Sopenharmony_ci	bool sum_ret = false;
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	list_for_each_entry_rcu(cur, &team->port_list, list) {
2362306a36Sopenharmony_ci		if (team_port_txable(cur)) {
2462306a36Sopenharmony_ci			if (last) {
2562306a36Sopenharmony_ci				skb2 = skb_clone(skb, GFP_ATOMIC);
2662306a36Sopenharmony_ci				if (skb2) {
2762306a36Sopenharmony_ci					ret = !team_dev_queue_xmit(team, last,
2862306a36Sopenharmony_ci								   skb2);
2962306a36Sopenharmony_ci					if (!sum_ret)
3062306a36Sopenharmony_ci						sum_ret = ret;
3162306a36Sopenharmony_ci				}
3262306a36Sopenharmony_ci			}
3362306a36Sopenharmony_ci			last = cur;
3462306a36Sopenharmony_ci		}
3562306a36Sopenharmony_ci	}
3662306a36Sopenharmony_ci	if (last) {
3762306a36Sopenharmony_ci		ret = !team_dev_queue_xmit(team, last, skb);
3862306a36Sopenharmony_ci		if (!sum_ret)
3962306a36Sopenharmony_ci			sum_ret = ret;
4062306a36Sopenharmony_ci	}
4162306a36Sopenharmony_ci	return sum_ret;
4262306a36Sopenharmony_ci}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic const struct team_mode_ops bc_mode_ops = {
4562306a36Sopenharmony_ci	.transmit		= bc_transmit,
4662306a36Sopenharmony_ci	.port_enter		= team_modeop_port_enter,
4762306a36Sopenharmony_ci	.port_change_dev_addr	= team_modeop_port_change_dev_addr,
4862306a36Sopenharmony_ci};
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic const struct team_mode bc_mode = {
5162306a36Sopenharmony_ci	.kind		= "broadcast",
5262306a36Sopenharmony_ci	.owner		= THIS_MODULE,
5362306a36Sopenharmony_ci	.ops		= &bc_mode_ops,
5462306a36Sopenharmony_ci	.lag_tx_type	= NETDEV_LAG_TX_TYPE_BROADCAST,
5562306a36Sopenharmony_ci};
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic int __init bc_init_module(void)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	return team_mode_register(&bc_mode);
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic void __exit bc_cleanup_module(void)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	team_mode_unregister(&bc_mode);
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cimodule_init(bc_init_module);
6862306a36Sopenharmony_cimodule_exit(bc_cleanup_module);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
7162306a36Sopenharmony_ciMODULE_AUTHOR("Jiri Pirko <jpirko@redhat.com>");
7262306a36Sopenharmony_ciMODULE_DESCRIPTION("Broadcast mode for team");
7362306a36Sopenharmony_ciMODULE_ALIAS_TEAM_MODE("broadcast");
74