18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * drivers/net/team/team_mode_broadcast.c - Broadcast mode for team
48c2ecf20Sopenharmony_ci * Copyright (c) 2012 Jiri Pirko <jpirko@redhat.com>
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/kernel.h>
88c2ecf20Sopenharmony_ci#include <linux/types.h>
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci#include <linux/init.h>
118c2ecf20Sopenharmony_ci#include <linux/errno.h>
128c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
138c2ecf20Sopenharmony_ci#include <linux/if_team.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_cistatic bool bc_transmit(struct team *team, struct sk_buff *skb)
168c2ecf20Sopenharmony_ci{
178c2ecf20Sopenharmony_ci	struct team_port *cur;
188c2ecf20Sopenharmony_ci	struct team_port *last = NULL;
198c2ecf20Sopenharmony_ci	struct sk_buff *skb2;
208c2ecf20Sopenharmony_ci	bool ret;
218c2ecf20Sopenharmony_ci	bool sum_ret = false;
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(cur, &team->port_list, list) {
248c2ecf20Sopenharmony_ci		if (team_port_txable(cur)) {
258c2ecf20Sopenharmony_ci			if (last) {
268c2ecf20Sopenharmony_ci				skb2 = skb_clone(skb, GFP_ATOMIC);
278c2ecf20Sopenharmony_ci				if (skb2) {
288c2ecf20Sopenharmony_ci					ret = !team_dev_queue_xmit(team, last,
298c2ecf20Sopenharmony_ci								   skb2);
308c2ecf20Sopenharmony_ci					if (!sum_ret)
318c2ecf20Sopenharmony_ci						sum_ret = ret;
328c2ecf20Sopenharmony_ci				}
338c2ecf20Sopenharmony_ci			}
348c2ecf20Sopenharmony_ci			last = cur;
358c2ecf20Sopenharmony_ci		}
368c2ecf20Sopenharmony_ci	}
378c2ecf20Sopenharmony_ci	if (last) {
388c2ecf20Sopenharmony_ci		ret = !team_dev_queue_xmit(team, last, skb);
398c2ecf20Sopenharmony_ci		if (!sum_ret)
408c2ecf20Sopenharmony_ci			sum_ret = ret;
418c2ecf20Sopenharmony_ci	}
428c2ecf20Sopenharmony_ci	return sum_ret;
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic const struct team_mode_ops bc_mode_ops = {
468c2ecf20Sopenharmony_ci	.transmit		= bc_transmit,
478c2ecf20Sopenharmony_ci	.port_enter		= team_modeop_port_enter,
488c2ecf20Sopenharmony_ci	.port_change_dev_addr	= team_modeop_port_change_dev_addr,
498c2ecf20Sopenharmony_ci};
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic const struct team_mode bc_mode = {
528c2ecf20Sopenharmony_ci	.kind		= "broadcast",
538c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
548c2ecf20Sopenharmony_ci	.ops		= &bc_mode_ops,
558c2ecf20Sopenharmony_ci	.lag_tx_type	= NETDEV_LAG_TX_TYPE_BROADCAST,
568c2ecf20Sopenharmony_ci};
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic int __init bc_init_module(void)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	return team_mode_register(&bc_mode);
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic void __exit bc_cleanup_module(void)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	team_mode_unregister(&bc_mode);
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cimodule_init(bc_init_module);
698c2ecf20Sopenharmony_cimodule_exit(bc_cleanup_module);
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
728c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jiri Pirko <jpirko@redhat.com>");
738c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Broadcast mode for team");
748c2ecf20Sopenharmony_ciMODULE_ALIAS_TEAM_MODE("broadcast");
75