soft-interface.c 13.9 KB
Newer Older
1
/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
 *
 * Marek Lindner, Simon Wunderlich
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of version 2 of the GNU General Public
 * License as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA
 */

#include "main.h"
#include "soft-interface.h"
#include "hard-interface.h"
#include "routing.h"
#include "send.h"
#include "bat_debugfs.h"
#include "translation-table.h"
#include "hash.h"
#include "gateway_common.h"
#include "gateway_client.h"
#include "bat_sysfs.h"
31
#include "originator.h"
32 33 34 35 36
#include <linux/slab.h>
#include <linux/ethtool.h>
#include <linux/etherdevice.h>
#include <linux/if_vlan.h>
#include "unicast.h"
37
#include "bridge_loop_avoidance.h"
38 39 40 41 42 43 44 45


static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd);
static void bat_get_drvinfo(struct net_device *dev,
			    struct ethtool_drvinfo *info);
static u32 bat_get_msglevel(struct net_device *dev);
static void bat_set_msglevel(struct net_device *dev, u32 value);
static u32 bat_get_link(struct net_device *dev);
46 47 48 49
static void batadv_get_strings(struct net_device *dev, u32 stringset, u8 *data);
static void batadv_get_ethtool_stats(struct net_device *dev,
				     struct ethtool_stats *stats, u64 *data);
static int batadv_get_sset_count(struct net_device *dev, int stringset);
50 51 52 53 54 55 56

static const struct ethtool_ops bat_ethtool_ops = {
	.get_settings = bat_get_settings,
	.get_drvinfo = bat_get_drvinfo,
	.get_msglevel = bat_get_msglevel,
	.set_msglevel = bat_set_msglevel,
	.get_link = bat_get_link,
57 58 59
	.get_strings = batadv_get_strings,
	.get_ethtool_stats = batadv_get_ethtool_stats,
	.get_sset_count = batadv_get_sset_count,
60 61
};

62
int batadv_skb_head_push(struct sk_buff *skb, unsigned int len)
63 64 65
{
	int result;

66
	/* TODO: We must check if we can release all references to non-payload
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
	 * data using skb_header_release in our skbs to allow skb_cow_header to
	 * work optimally. This means that those skbs are not allowed to read
	 * or write any data which is before the current position of skb->data
	 * after that call and thus allow other skbs with the same data buffer
	 * to write freely in that area.
	 */
	result = skb_cow_head(skb, len);
	if (result < 0)
		return result;

	skb_push(skb, len);
	return 0;
}

static int interface_open(struct net_device *dev)
{
	netif_start_queue(dev);
	return 0;
}

static int interface_release(struct net_device *dev)
{
	netif_stop_queue(dev);
	return 0;
}

static struct net_device_stats *interface_stats(struct net_device *dev)
{
	struct bat_priv *bat_priv = netdev_priv(dev);
	return &bat_priv->stats;
}

static int interface_set_mac_addr(struct net_device *dev, void *p)
{
	struct bat_priv *bat_priv = netdev_priv(dev);
	struct sockaddr *addr = p;

	if (!is_valid_ether_addr(addr->sa_data))
		return -EADDRNOTAVAIL;

107
	/* only modify transtable if it has been initialized before */
108
	if (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) {
109 110 111
		batadv_tt_local_remove(bat_priv, dev->dev_addr,
				       "mac address changed", false);
		batadv_tt_local_add(dev, addr->sa_data, NULL_IFINDEX);
112 113 114
	}

	memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
115
	dev->addr_assign_type &= ~NET_ADDR_RANDOM;
116 117 118 119 120 121
	return 0;
}

static int interface_change_mtu(struct net_device *dev, int new_mtu)
{
	/* check ranges */
122
	if ((new_mtu < 68) || (new_mtu > batadv_hardif_min_mtu(dev)))
123 124 125 126 127 128 129
		return -EINVAL;

	dev->mtu = new_mtu;

	return 0;
}

130
static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
131 132 133
{
	struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
	struct bat_priv *bat_priv = netdev_priv(soft_iface);
134
	struct hard_iface *primary_if = NULL;
135 136
	struct bcast_packet *bcast_packet;
	struct vlan_ethhdr *vhdr;
137 138
	static const uint8_t stp_addr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, 0x00,
						   0x00};
139
	unsigned int header_len = 0;
140
	int data_len = skb->len, ret;
141
	short vid __maybe_unused = -1;
142
	bool do_bcast = false;
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159

	if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
		goto dropped;

	soft_iface->trans_start = jiffies;

	switch (ntohs(ethhdr->h_proto)) {
	case ETH_P_8021Q:
		vhdr = (struct vlan_ethhdr *)skb->data;
		vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK;

		if (ntohs(vhdr->h_vlan_encapsulated_proto) != ETH_P_BATMAN)
			break;

		/* fall through */
	case ETH_P_BATMAN:
		goto dropped;
160
	}
161

162
	if (batadv_bla_tx(bat_priv, skb, vid))
163 164
		goto dropped;

165
	/* Register the client MAC in the transtable */
166
	batadv_tt_local_add(soft_iface, ethhdr->h_source, skb->skb_iif);
167

168 169 170 171 172 173
	/* don't accept stp packets. STP does not help in meshes.
	 * better use the bridge loop avoidance ...
	 */
	if (compare_eth(ethhdr->h_dest, stp_addr))
		goto dropped;

174 175
	if (is_multicast_ether_addr(ethhdr->h_dest)) {
		do_bcast = true;
176

177 178 179
		switch (atomic_read(&bat_priv->gw_mode)) {
		case GW_MODE_SERVER:
			/* gateway servers should not send dhcp
180 181
			 * requests into the mesh
			 */
182
			ret = batadv_gw_is_dhcp_target(skb, &header_len);
183 184 185 186 187
			if (ret)
				goto dropped;
			break;
		case GW_MODE_CLIENT:
			/* gateway clients should send dhcp requests
188 189
			 * via unicast to their gateway
			 */
190
			ret = batadv_gw_is_dhcp_target(skb, &header_len);
191 192 193 194 195 196 197
			if (ret)
				do_bcast = false;
			break;
		case GW_MODE_OFF:
		default:
			break;
		}
198 199 200 201
	}

	/* ethernet packet should be broadcasted */
	if (do_bcast) {
202 203
		primary_if = primary_if_get_selected(bat_priv);
		if (!primary_if)
204 205
			goto dropped;

206
		if (batadv_skb_head_push(skb, sizeof(*bcast_packet)) < 0)
207 208 209
			goto dropped;

		bcast_packet = (struct bcast_packet *)skb->data;
210 211
		bcast_packet->header.version = COMPAT_VERSION;
		bcast_packet->header.ttl = TTL;
212 213

		/* batman packet type: broadcast */
214
		bcast_packet->header.packet_type = BAT_BCAST;
215 216

		/* hw address of first interface is the orig mac because only
217 218
		 * this mac is known throughout the mesh
		 */
219
		memcpy(bcast_packet->orig,
220
		       primary_if->net_dev->dev_addr, ETH_ALEN);
221 222 223 224 225

		/* set broadcast sequence number */
		bcast_packet->seqno =
			htonl(atomic_inc_return(&bat_priv->bcast_seqno));

226
		batadv_add_bcast_packet_to_list(bat_priv, skb, 1);
227 228

		/* a copy is stored in the bcast list, therefore removing
229 230
		 * the original skb.
		 */
231 232 233 234
		kfree_skb(skb);

	/* unicast packet */
	} else {
235
		if (atomic_read(&bat_priv->gw_mode) != GW_MODE_OFF) {
236
			ret = batadv_gw_out_of_range(bat_priv, skb, ethhdr);
237 238 239 240
			if (ret)
				goto dropped;
		}

241
		ret = batadv_unicast_send_skb(skb, bat_priv);
242 243 244 245 246 247 248 249 250 251 252 253 254
		if (ret != 0)
			goto dropped_freed;
	}

	bat_priv->stats.tx_packets++;
	bat_priv->stats.tx_bytes += data_len;
	goto end;

dropped:
	kfree_skb(skb);
dropped_freed:
	bat_priv->stats.tx_dropped++;
end:
255 256
	if (primary_if)
		hardif_free_ref(primary_if);
257 258 259
	return NETDEV_TX_OK;
}

260 261 262
void batadv_interface_rx(struct net_device *soft_iface,
			 struct sk_buff *skb, struct hard_iface *recv_if,
			 int hdr_size)
263 264 265 266
{
	struct bat_priv *bat_priv = netdev_priv(soft_iface);
	struct ethhdr *ethhdr;
	struct vlan_ethhdr *vhdr;
267
	short vid __maybe_unused = -1;
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295

	/* check if enough space is available for pulling, and pull */
	if (!pskb_may_pull(skb, hdr_size))
		goto dropped;

	skb_pull_rcsum(skb, hdr_size);
	skb_reset_mac_header(skb);

	ethhdr = (struct ethhdr *)skb_mac_header(skb);

	switch (ntohs(ethhdr->h_proto)) {
	case ETH_P_8021Q:
		vhdr = (struct vlan_ethhdr *)skb->data;
		vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK;

		if (ntohs(vhdr->h_vlan_encapsulated_proto) != ETH_P_BATMAN)
			break;

		/* fall through */
	case ETH_P_BATMAN:
		goto dropped;
	}

	/* skb->dev & skb->pkt_type are set here */
	if (unlikely(!pskb_may_pull(skb, ETH_HLEN)))
		goto dropped;
	skb->protocol = eth_type_trans(skb, soft_iface);

L
Lucas De Marchi 已提交
296
	/* should not be necessary anymore as we use skb_pull_rcsum()
297
	 * TODO: please verify this and remove this TODO
298 299
	 * -- Dec 21st 2009, Simon Wunderlich
	 */
300

301
	/* skb->ip_summed = CHECKSUM_UNNECESSARY; */
302 303

	bat_priv->stats.rx_packets++;
304
	bat_priv->stats.rx_bytes += skb->len + ETH_HLEN;
305 306 307

	soft_iface->last_rx = jiffies;

308
	if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source, ethhdr->h_dest))
309 310
		goto dropped;

311 312 313
	/* Let the bridge loop avoidance check the packet. If will
	 * not handle it, we can safely push it up.
	 */
314
	if (batadv_bla_rx(bat_priv, skb, vid))
315 316
		goto out;

317
	netif_rx(skb);
318
	goto out;
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343

dropped:
	kfree_skb(skb);
out:
	return;
}

static const struct net_device_ops bat_netdev_ops = {
	.ndo_open = interface_open,
	.ndo_stop = interface_release,
	.ndo_get_stats = interface_stats,
	.ndo_set_mac_address = interface_set_mac_addr,
	.ndo_change_mtu = interface_change_mtu,
	.ndo_start_xmit = interface_tx,
	.ndo_validate_addr = eth_validate_addr
};

static void interface_setup(struct net_device *dev)
{
	struct bat_priv *priv = netdev_priv(dev);

	ether_setup(dev);

	dev->netdev_ops = &bat_netdev_ops;
	dev->destructor = free_netdev;
344
	dev->tx_queue_len = 0;
345

346
	/* can't call min_mtu, because the needed variables
347 348 349
	 * have not been initialized yet
	 */
	dev->mtu = ETH_DATA_LEN;
350 351
	/* reserve more space in the skbuff for our header */
	dev->hard_header_len = BAT_HEADER_LEN;
352 353

	/* generate random address */
354
	eth_hw_addr_random(dev);
355 356 357

	SET_ETHTOOL_OPS(dev, &bat_ethtool_ops);

358
	memset(priv, 0, sizeof(*priv));
359 360
}

361
struct net_device *batadv_softif_create(const char *name)
362 363 364 365 366
{
	struct net_device *soft_iface;
	struct bat_priv *bat_priv;
	int ret;

367
	soft_iface = alloc_netdev(sizeof(*bat_priv), name, interface_setup);
368

369
	if (!soft_iface)
370 371
		goto out;

372
	ret = register_netdevice(soft_iface);
373 374 375 376 377 378 379 380 381 382
	if (ret < 0) {
		pr_err("Unable to register the batman interface '%s': %i\n",
		       name, ret);
		goto free_soft_iface;
	}

	bat_priv = netdev_priv(soft_iface);

	atomic_set(&bat_priv->aggregated_ogms, 1);
	atomic_set(&bat_priv->bonding, 0);
383
	atomic_set(&bat_priv->bridge_loop_avoidance, 0);
384
	atomic_set(&bat_priv->ap_isolation, 0);
385 386 387 388 389
	atomic_set(&bat_priv->vis_mode, VIS_TYPE_CLIENT_UPDATE);
	atomic_set(&bat_priv->gw_mode, GW_MODE_OFF);
	atomic_set(&bat_priv->gw_sel_class, 20);
	atomic_set(&bat_priv->gw_bandwidth, 41);
	atomic_set(&bat_priv->orig_interval, 1000);
390
	atomic_set(&bat_priv->hop_penalty, 30);
391 392 393 394 395 396 397
	atomic_set(&bat_priv->log_level, 0);
	atomic_set(&bat_priv->fragmentation, 1);
	atomic_set(&bat_priv->bcast_queue_left, BCAST_QUEUE_LEN);
	atomic_set(&bat_priv->batman_queue_left, BATMAN_QUEUE_LEN);

	atomic_set(&bat_priv->mesh_state, MESH_INACTIVE);
	atomic_set(&bat_priv->bcast_seqno, 1);
398 399 400
	atomic_set(&bat_priv->ttvn, 0);
	atomic_set(&bat_priv->tt_local_changes, 0);
	atomic_set(&bat_priv->tt_ogm_append_cnt, 0);
401
	atomic_set(&bat_priv->bla_num_requests, 0);
402 403 404

	bat_priv->tt_buff = NULL;
	bat_priv->tt_buff_len = 0;
405
	bat_priv->tt_poss_change = false;
406 407 408 409

	bat_priv->primary_if = NULL;
	bat_priv->num_ifaces = 0;

410 411 412 413 414
	bat_priv->bat_counters = __alloc_percpu(sizeof(uint64_t) * BAT_CNT_NUM,
						__alignof__(uint64_t));
	if (!bat_priv->bat_counters)
		goto unreg_soft_iface;

415
	ret = batadv_algo_select(bat_priv, batadv_routing_algo);
416
	if (ret < 0)
417
		goto free_bat_counters;
418

419
	ret = batadv_sysfs_add_meshif(soft_iface);
420
	if (ret < 0)
421
		goto free_bat_counters;
422

423
	ret = batadv_debugfs_add_meshif(soft_iface);
424 425 426
	if (ret < 0)
		goto unreg_sysfs;

427
	ret = batadv_mesh_init(soft_iface);
428 429 430 431 432 433
	if (ret < 0)
		goto unreg_debugfs;

	return soft_iface;

unreg_debugfs:
434
	batadv_debugfs_del_meshif(soft_iface);
435
unreg_sysfs:
436
	batadv_sysfs_del_meshif(soft_iface);
437 438
free_bat_counters:
	free_percpu(bat_priv->bat_counters);
439
unreg_soft_iface:
440
	unregister_netdevice(soft_iface);
441 442 443 444 445 446 447 448
	return NULL;

free_soft_iface:
	free_netdev(soft_iface);
out:
	return NULL;
}

449
void batadv_softif_destroy(struct net_device *soft_iface)
450
{
451
	batadv_debugfs_del_meshif(soft_iface);
452
	batadv_sysfs_del_meshif(soft_iface);
453
	batadv_mesh_free(soft_iface);
454 455 456
	unregister_netdevice(soft_iface);
}

457
int batadv_softif_is_valid(const struct net_device *net_dev)
458 459 460 461 462 463 464
{
	if (net_dev->netdev_ops->ndo_start_xmit == interface_tx)
		return 1;

	return 0;
}

465 466 467 468 469
/* ethtool */
static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
	cmd->supported = 0;
	cmd->advertising = 0;
470
	ethtool_cmd_speed_set(cmd, SPEED_10);
471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503
	cmd->duplex = DUPLEX_FULL;
	cmd->port = PORT_TP;
	cmd->phy_address = 0;
	cmd->transceiver = XCVR_INTERNAL;
	cmd->autoneg = AUTONEG_DISABLE;
	cmd->maxtxpkt = 0;
	cmd->maxrxpkt = 0;

	return 0;
}

static void bat_get_drvinfo(struct net_device *dev,
			    struct ethtool_drvinfo *info)
{
	strcpy(info->driver, "B.A.T.M.A.N. advanced");
	strcpy(info->version, SOURCE_VERSION);
	strcpy(info->fw_version, "N/A");
	strcpy(info->bus_info, "batman");
}

static u32 bat_get_msglevel(struct net_device *dev)
{
	return -EOPNOTSUPP;
}

static void bat_set_msglevel(struct net_device *dev, u32 value)
{
}

static u32 bat_get_link(struct net_device *dev)
{
	return 1;
}
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551

/* Inspired by drivers/net/ethernet/dlink/sundance.c:1702
 * Declare each description string in struct.name[] to get fixed sized buffer
 * and compile time checking for strings longer than ETH_GSTRING_LEN.
 */
static const struct {
	const char name[ETH_GSTRING_LEN];
} bat_counters_strings[] = {
	{ "forward" },
	{ "forward_bytes" },
	{ "mgmt_tx" },
	{ "mgmt_tx_bytes" },
	{ "mgmt_rx" },
	{ "mgmt_rx_bytes" },
	{ "tt_request_tx" },
	{ "tt_request_rx" },
	{ "tt_response_tx" },
	{ "tt_response_rx" },
	{ "tt_roam_adv_tx" },
	{ "tt_roam_adv_rx" },
};

static void batadv_get_strings(struct net_device *dev, uint32_t stringset,
			       uint8_t *data)
{
	if (stringset == ETH_SS_STATS)
		memcpy(data, bat_counters_strings,
		       sizeof(bat_counters_strings));
}

static void batadv_get_ethtool_stats(struct net_device *dev,
				     struct ethtool_stats *stats,
				     uint64_t *data)
{
	struct bat_priv *bat_priv = netdev_priv(dev);
	int i;

	for (i = 0; i < BAT_CNT_NUM; i++)
		data[i] = batadv_sum_counter(bat_priv, i);
}

static int batadv_get_sset_count(struct net_device *dev, int stringset)
{
	if (stringset == ETH_SS_STATS)
		return BAT_CNT_NUM;

	return -EOPNOTSUPP;
}