hsr_slave.c 4.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
/* Copyright 2011-2014 Autronica Fire and Security AS
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * Author(s):
 *	2011-2014 Arvid Brodin, arvid.brodin@alten.se
 */

#include "hsr_slave.h"
#include <linux/etherdevice.h>
14
#include <linux/if_arp.h>
15
#include "hsr_main.h"
16
#include "hsr_device.h"
A
Arvid Brodin 已提交
17
#include "hsr_forward.h"
18 19 20
#include "hsr_framereg.h"


A
Arvid Brodin 已提交
21 22 23 24
static rx_handler_result_t hsr_handle_frame(struct sk_buff **pskb)
{
	struct sk_buff *skb = *pskb;
	struct hsr_port *port;
P
Peter Heise 已提交
25
	u16 protocol;
A
Arvid Brodin 已提交
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40

	if (!skb_mac_header_was_set(skb)) {
		WARN_ONCE(1, "%s: skb invalid", __func__);
		return RX_HANDLER_PASS;
	}

	rcu_read_lock(); /* hsr->node_db, hsr->ports */
	port = hsr_port_get_rcu(skb->dev);

	if (hsr_addr_is_self(port->hsr, eth_hdr(skb)->h_source)) {
		/* Directly kill frames sent by ourselves */
		kfree_skb(skb);
		goto finish_consume;
	}

P
Peter Heise 已提交
41 42
	protocol = eth_hdr(skb)->h_proto;
	if (protocol != htons(ETH_P_PRP) && protocol != htons(ETH_P_HSR))
A
Arvid Brodin 已提交
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
		goto finish_pass;

	skb_push(skb, ETH_HLEN);

	hsr_forward_skb(skb, port);

finish_consume:
	rcu_read_unlock(); /* hsr->node_db, hsr->ports */
	return RX_HANDLER_CONSUMED;

finish_pass:
	rcu_read_unlock(); /* hsr->node_db, hsr->ports */
	return RX_HANDLER_PASS;
}

bool hsr_port_exists(const struct net_device *dev)
{
	return rcu_access_pointer(dev->rx_handler) == hsr_handle_frame;
}


64
static int hsr_check_dev_ok(struct net_device *dev)
65 66 67 68 69 70 71 72 73 74 75 76 77 78
{
	/* Don't allow HSR on non-ethernet like devices */
	if ((dev->flags & IFF_LOOPBACK) || (dev->type != ARPHRD_ETHER) ||
	    (dev->addr_len != ETH_ALEN)) {
		netdev_info(dev, "Cannot use loopback or non-ethernet device as HSR slave.\n");
		return -EINVAL;
	}

	/* Don't allow enslaving hsr devices */
	if (is_hsr_master(dev)) {
		netdev_info(dev, "Cannot create trees of HSR devices.\n");
		return -EINVAL;
	}

79
	if (hsr_port_exists(dev)) {
80 81 82 83 84 85 86 87 88
		netdev_info(dev, "This device is already a HSR slave.\n");
		return -EINVAL;
	}

	if (dev->priv_flags & IFF_802_1Q_VLAN) {
		netdev_info(dev, "HSR on top of VLAN is not yet supported in this driver.\n");
		return -EINVAL;
	}

A
Arvid Brodin 已提交
89 90 91 92 93
	if (dev->priv_flags & IFF_DONT_BRIDGE) {
		netdev_info(dev, "This device does not support bridging.\n");
		return -EOPNOTSUPP;
	}

94 95 96 97 98 99 100 101
	/* HSR over bonded devices has not been tested, but I'm not sure it
	 * won't work...
	 */

	return 0;
}


102 103
/* Setup device to be added to the HSR bridge. */
static int hsr_portdev_setup(struct net_device *dev, struct hsr_port *port)
104 105 106 107 108 109
{
	int res;

	dev_hold(dev);
	res = dev_set_promiscuity(dev, 1);
	if (res)
110
		goto fail_promiscuity;
111

112 113 114 115
	/* FIXME:
	 * What does net device "adjacency" mean? Should we do
	 * res = netdev_master_upper_dev_link(port->dev, port->hsr->dev); ?
	 */
116

A
Arvid Brodin 已提交
117 118 119 120 121
	res = netdev_rx_handler_register(dev, hsr_handle_frame, port);
	if (res)
		goto fail_rx_handler;
	dev_disable_lro(dev);

122 123 124 125
	return 0;

fail_rx_handler:
	dev_set_promiscuity(dev, -1);
126
fail_promiscuity:
127
	dev_put(dev);
128

129 130 131
	return res;
}

132 133
int hsr_add_port(struct hsr_priv *hsr, struct net_device *dev,
		 enum hsr_port_type type)
134
{
135 136
	struct hsr_port *port, *master;
	int res;
137

138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
	if (type != HSR_PT_MASTER) {
		res = hsr_check_dev_ok(dev);
		if (res)
			return res;
	}

	port = hsr_port_get_hsr(hsr, type);
	if (port != NULL)
		return -EBUSY;	/* This port already exists */

	port = kzalloc(sizeof(*port), GFP_KERNEL);
	if (port == NULL)
		return -ENOMEM;

	if (type != HSR_PT_MASTER) {
		res = hsr_portdev_setup(dev, port);
		if (res)
			goto fail_dev_setup;
	}

	port->hsr = hsr;
	port->dev = dev;
	port->type = type;

	list_add_tail_rcu(&port->port_list, &hsr->ports);
	synchronize_rcu();

	master = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
166
	netdev_update_features(master->dev);
167
	dev_set_mtu(master->dev, hsr_get_max_mtu(hsr));
168

169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
	return 0;

fail_dev_setup:
	kfree(port);
	return res;
}

void hsr_del_port(struct hsr_port *port)
{
	struct hsr_priv *hsr;
	struct hsr_port *master;

	hsr = port->hsr;
	master = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
	list_del_rcu(&port->port_list);

	if (port != master) {
186 187 188 189
		if (master != NULL) {
			netdev_update_features(master->dev);
			dev_set_mtu(master->dev, hsr_get_max_mtu(hsr));
		}
190 191
		netdev_rx_handler_unregister(port->dev);
		dev_set_promiscuity(port->dev, -1);
192 193
	}

194 195 196 197
	/* FIXME?
	 * netdev_upper_dev_unlink(port->dev, port->hsr->dev);
	 */

198
	synchronize_rcu();
199 200 201

	if (port != master)
		dev_put(port->dev);
202
}