Commit ea407f0b authored by David S. Miller's avatar David S. Miller

Merge tag 'batman-adv-for-davem' of git://git.open-mesh.org/linux-merge

Included changes:
- A fix for the network coding component which has been added within the last
  pull request (so it is in linux-3.10). The problem has been spotted thanks to
  Fengguang Wu's automated daily checks on our tree.
- Implementation of the RTNL API for virtual interface creation/deletion and slave
  manipulation
- substitution of seq_printf with seq_puts when possible
- minor cleanups
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 9631d79e 0c814653
# #
# Copyright (C) 2007-2012 B.A.T.M.A.N. contributors: # Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
# #
# Marek Lindner, Simon Wunderlich # Marek Lindner, Simon Wunderlich
# #
......
...@@ -500,7 +500,7 @@ int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset) ...@@ -500,7 +500,7 @@ int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset)
rcu_read_unlock(); rcu_read_unlock();
if (gw_count == 0) if (gw_count == 0)
seq_printf(seq, "No gateways in range ...\n"); seq_puts(seq, "No gateways in range ...\n");
out: out:
if (primary_if) if (primary_if)
......
...@@ -307,11 +307,35 @@ batadv_hardif_deactivate_interface(struct batadv_hard_iface *hard_iface) ...@@ -307,11 +307,35 @@ batadv_hardif_deactivate_interface(struct batadv_hard_iface *hard_iface)
batadv_update_min_mtu(hard_iface->soft_iface); batadv_update_min_mtu(hard_iface->soft_iface);
} }
/**
* batadv_master_del_slave - remove hard_iface from the current master interface
* @slave: the interface enslaved in another master
* @master: the master from which slave has to be removed
*
* Invoke ndo_del_slave on master passing slave as argument. In this way slave
* is free'd and master can correctly change its internal state.
* Return 0 on success, a negative value representing the error otherwise
*/
static int batadv_master_del_slave(struct batadv_hard_iface *slave,
struct net_device *master)
{
int ret;
if (!master)
return 0;
ret = -EBUSY;
if (master->netdev_ops->ndo_del_slave)
ret = master->netdev_ops->ndo_del_slave(master, slave->net_dev);
return ret;
}
int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
const char *iface_name) const char *iface_name)
{ {
struct batadv_priv *bat_priv; struct batadv_priv *bat_priv;
struct net_device *soft_iface; struct net_device *soft_iface, *master;
__be16 ethertype = __constant_htons(ETH_P_BATMAN); __be16 ethertype = __constant_htons(ETH_P_BATMAN);
int ret; int ret;
...@@ -321,11 +345,6 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, ...@@ -321,11 +345,6 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
if (!atomic_inc_not_zero(&hard_iface->refcount)) if (!atomic_inc_not_zero(&hard_iface->refcount))
goto out; goto out;
/* hard-interface is part of a bridge */
if (hard_iface->net_dev->priv_flags & IFF_BRIDGE_PORT)
pr_err("You are about to enable batman-adv on '%s' which already is part of a bridge. Unless you know exactly what you are doing this is probably wrong and won't work the way you think it would.\n",
hard_iface->net_dev->name);
soft_iface = dev_get_by_name(&init_net, iface_name); soft_iface = dev_get_by_name(&init_net, iface_name);
if (!soft_iface) { if (!soft_iface) {
...@@ -347,12 +366,24 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, ...@@ -347,12 +366,24 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
goto err_dev; goto err_dev;
} }
/* check if the interface is enslaved in another virtual one and
* in that case unlink it first
*/
master = netdev_master_upper_dev_get(hard_iface->net_dev);
ret = batadv_master_del_slave(hard_iface, master);
if (ret)
goto err_dev;
hard_iface->soft_iface = soft_iface; hard_iface->soft_iface = soft_iface;
bat_priv = netdev_priv(hard_iface->soft_iface); bat_priv = netdev_priv(hard_iface->soft_iface);
ret = netdev_master_upper_dev_link(hard_iface->net_dev, soft_iface);
if (ret)
goto err_dev;
ret = bat_priv->bat_algo_ops->bat_iface_enable(hard_iface); ret = bat_priv->bat_algo_ops->bat_iface_enable(hard_iface);
if (ret < 0) if (ret < 0)
goto err_dev; goto err_upper;
hard_iface->if_num = bat_priv->num_ifaces; hard_iface->if_num = bat_priv->num_ifaces;
bat_priv->num_ifaces++; bat_priv->num_ifaces++;
...@@ -362,7 +393,7 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, ...@@ -362,7 +393,7 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
bat_priv->bat_algo_ops->bat_iface_disable(hard_iface); bat_priv->bat_algo_ops->bat_iface_disable(hard_iface);
bat_priv->num_ifaces--; bat_priv->num_ifaces--;
hard_iface->if_status = BATADV_IF_NOT_IN_USE; hard_iface->if_status = BATADV_IF_NOT_IN_USE;
goto err_dev; goto err_upper;
} }
hard_iface->batman_adv_ptype.type = ethertype; hard_iface->batman_adv_ptype.type = ethertype;
...@@ -401,14 +432,18 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, ...@@ -401,14 +432,18 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
out: out:
return 0; return 0;
err_upper:
netdev_upper_dev_unlink(hard_iface->net_dev, soft_iface);
err_dev: err_dev:
hard_iface->soft_iface = NULL;
dev_put(soft_iface); dev_put(soft_iface);
err: err:
batadv_hardif_free_ref(hard_iface); batadv_hardif_free_ref(hard_iface);
return ret; return ret;
} }
void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface) void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface,
enum batadv_hard_if_cleanup autodel)
{ {
struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
struct batadv_hard_iface *primary_if = NULL; struct batadv_hard_iface *primary_if = NULL;
...@@ -446,9 +481,10 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface) ...@@ -446,9 +481,10 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface)
dev_put(hard_iface->soft_iface); dev_put(hard_iface->soft_iface);
/* nobody uses this interface anymore */ /* nobody uses this interface anymore */
if (!bat_priv->num_ifaces) if (!bat_priv->num_ifaces && autodel == BATADV_IF_CLEANUP_AUTO)
batadv_softif_destroy(hard_iface->soft_iface); batadv_softif_destroy_sysfs(hard_iface->soft_iface);
netdev_upper_dev_unlink(hard_iface->net_dev, hard_iface->soft_iface);
hard_iface->soft_iface = NULL; hard_iface->soft_iface = NULL;
batadv_hardif_free_ref(hard_iface); batadv_hardif_free_ref(hard_iface);
...@@ -533,7 +569,8 @@ static void batadv_hardif_remove_interface(struct batadv_hard_iface *hard_iface) ...@@ -533,7 +569,8 @@ static void batadv_hardif_remove_interface(struct batadv_hard_iface *hard_iface)
/* first deactivate interface */ /* first deactivate interface */
if (hard_iface->if_status != BATADV_IF_NOT_IN_USE) if (hard_iface->if_status != BATADV_IF_NOT_IN_USE)
batadv_hardif_disable_interface(hard_iface); batadv_hardif_disable_interface(hard_iface,
BATADV_IF_CLEANUP_AUTO);
if (hard_iface->if_status != BATADV_IF_NOT_IN_USE) if (hard_iface->if_status != BATADV_IF_NOT_IN_USE)
return; return;
...@@ -563,6 +600,11 @@ static int batadv_hard_if_event(struct notifier_block *this, ...@@ -563,6 +600,11 @@ static int batadv_hard_if_event(struct notifier_block *this,
struct batadv_hard_iface *primary_if = NULL; struct batadv_hard_iface *primary_if = NULL;
struct batadv_priv *bat_priv; struct batadv_priv *bat_priv;
if (batadv_softif_is_valid(net_dev) && event == NETDEV_REGISTER) {
batadv_sysfs_add_meshif(net_dev);
return NOTIFY_DONE;
}
hard_iface = batadv_hardif_get_by_netdev(net_dev); hard_iface = batadv_hardif_get_by_netdev(net_dev);
if (!hard_iface && event == NETDEV_REGISTER) if (!hard_iface && event == NETDEV_REGISTER)
hard_iface = batadv_hardif_add_interface(net_dev); hard_iface = batadv_hardif_add_interface(net_dev);
......
...@@ -29,13 +29,24 @@ enum batadv_hard_if_state { ...@@ -29,13 +29,24 @@ enum batadv_hard_if_state {
BATADV_IF_I_WANT_YOU, BATADV_IF_I_WANT_YOU,
}; };
/**
* enum batadv_hard_if_cleanup - Cleanup modi for soft_iface after slave removal
* @BATADV_IF_CLEANUP_KEEP: Don't automatically delete soft-interface
* @BATADV_IF_CLEANUP_AUTO: Delete soft-interface after last slave was removed
*/
enum batadv_hard_if_cleanup {
BATADV_IF_CLEANUP_KEEP,
BATADV_IF_CLEANUP_AUTO,
};
extern struct notifier_block batadv_hard_if_notifier; extern struct notifier_block batadv_hard_if_notifier;
struct batadv_hard_iface* struct batadv_hard_iface*
batadv_hardif_get_by_netdev(const struct net_device *net_dev); batadv_hardif_get_by_netdev(const struct net_device *net_dev);
int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
const char *iface_name); const char *iface_name);
void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface); void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface,
enum batadv_hard_if_cleanup autodel);
void batadv_hardif_remove_interfaces(void); void batadv_hardif_remove_interfaces(void);
int batadv_hardif_min_mtu(struct net_device *soft_iface); int batadv_hardif_min_mtu(struct net_device *soft_iface);
void batadv_update_min_mtu(struct net_device *soft_iface); void batadv_update_min_mtu(struct net_device *soft_iface);
......
...@@ -71,6 +71,7 @@ static int __init batadv_init(void) ...@@ -71,6 +71,7 @@ static int __init batadv_init(void)
batadv_debugfs_init(); batadv_debugfs_init();
register_netdevice_notifier(&batadv_hard_if_notifier); register_netdevice_notifier(&batadv_hard_if_notifier);
rtnl_link_register(&batadv_link_ops);
pr_info("B.A.T.M.A.N. advanced %s (compatibility version %i) loaded\n", pr_info("B.A.T.M.A.N. advanced %s (compatibility version %i) loaded\n",
BATADV_SOURCE_VERSION, BATADV_COMPAT_VERSION); BATADV_SOURCE_VERSION, BATADV_COMPAT_VERSION);
...@@ -81,6 +82,7 @@ static int __init batadv_init(void) ...@@ -81,6 +82,7 @@ static int __init batadv_init(void)
static void __exit batadv_exit(void) static void __exit batadv_exit(void)
{ {
batadv_debugfs_destroy(); batadv_debugfs_destroy();
rtnl_link_unregister(&batadv_link_ops);
unregister_netdevice_notifier(&batadv_hard_if_notifier); unregister_netdevice_notifier(&batadv_hard_if_notifier);
batadv_hardif_remove_interfaces(); batadv_hardif_remove_interfaces();
...@@ -417,7 +419,7 @@ int batadv_algo_seq_print_text(struct seq_file *seq, void *offset) ...@@ -417,7 +419,7 @@ int batadv_algo_seq_print_text(struct seq_file *seq, void *offset)
{ {
struct batadv_algo_ops *bat_algo_ops; struct batadv_algo_ops *bat_algo_ops;
seq_printf(seq, "Available routing algorithms:\n"); seq_puts(seq, "Available routing algorithms:\n");
hlist_for_each_entry(bat_algo_ops, &batadv_algo_list, list) { hlist_for_each_entry(bat_algo_ops, &batadv_algo_list, list) {
seq_printf(seq, "%s\n", bat_algo_ops->name); seq_printf(seq, "%s\n", bat_algo_ops->name);
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#define BATADV_DRIVER_DEVICE "batman-adv" #define BATADV_DRIVER_DEVICE "batman-adv"
#ifndef BATADV_SOURCE_VERSION #ifndef BATADV_SOURCE_VERSION
#define BATADV_SOURCE_VERSION "2013.1.0" #define BATADV_SOURCE_VERSION "2013.2.0"
#endif #endif
/* B.A.T.M.A.N. parameters */ /* B.A.T.M.A.N. parameters */
...@@ -152,6 +152,7 @@ enum batadv_uev_type { ...@@ -152,6 +152,7 @@ enum batadv_uev_type {
#include <linux/percpu.h> #include <linux/percpu.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <net/sock.h> /* struct sock */ #include <net/sock.h> /* struct sock */
#include <net/rtnetlink.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include "types.h" #include "types.h"
......
...@@ -654,7 +654,7 @@ static bool batadv_can_nc_with_orig(struct batadv_priv *bat_priv, ...@@ -654,7 +654,7 @@ static bool batadv_can_nc_with_orig(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node, struct batadv_orig_node *orig_node,
struct batadv_ogm_packet *ogm_packet) struct batadv_ogm_packet *ogm_packet)
{ {
if (orig_node->last_real_seqno != ogm_packet->seqno) if (orig_node->last_real_seqno != ntohl(ogm_packet->seqno))
return false; return false;
if (orig_node->last_ttl != ogm_packet->header.ttl + 1) if (orig_node->last_ttl != ogm_packet->header.ttl + 1)
return false; return false;
...@@ -1760,23 +1760,23 @@ int batadv_nc_nodes_seq_print_text(struct seq_file *seq, void *offset) ...@@ -1760,23 +1760,23 @@ int batadv_nc_nodes_seq_print_text(struct seq_file *seq, void *offset)
hlist_for_each_entry_rcu(orig_node, head, hash_entry) { hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
seq_printf(seq, "Node: %pM\n", orig_node->orig); seq_printf(seq, "Node: %pM\n", orig_node->orig);
seq_printf(seq, " Ingoing: "); seq_puts(seq, " Ingoing: ");
/* For each in_nc_node to this orig_node */ /* For each in_nc_node to this orig_node */
list_for_each_entry_rcu(nc_node, list_for_each_entry_rcu(nc_node,
&orig_node->in_coding_list, &orig_node->in_coding_list,
list) list)
seq_printf(seq, "%pM ", seq_printf(seq, "%pM ",
nc_node->addr); nc_node->addr);
seq_printf(seq, "\n"); seq_puts(seq, "\n");
seq_printf(seq, " Outgoing: "); seq_puts(seq, " Outgoing: ");
/* For out_nc_node to this orig_node */ /* For out_nc_node to this orig_node */
list_for_each_entry_rcu(nc_node, list_for_each_entry_rcu(nc_node,
&orig_node->out_coding_list, &orig_node->out_coding_list,
list) list)
seq_printf(seq, "%pM ", seq_printf(seq, "%pM ",
nc_node->addr); nc_node->addr);
seq_printf(seq, "\n\n"); seq_puts(seq, "\n\n");
} }
rcu_read_unlock(); rcu_read_unlock();
} }
......
...@@ -465,7 +465,7 @@ int batadv_orig_seq_print_text(struct seq_file *seq, void *offset) ...@@ -465,7 +465,7 @@ int batadv_orig_seq_print_text(struct seq_file *seq, void *offset)
neigh_node_tmp->tq_avg); neigh_node_tmp->tq_avg);
} }
seq_printf(seq, "\n"); seq_puts(seq, "\n");
batman_count++; batman_count++;
next: next:
...@@ -475,7 +475,7 @@ int batadv_orig_seq_print_text(struct seq_file *seq, void *offset) ...@@ -475,7 +475,7 @@ int batadv_orig_seq_print_text(struct seq_file *seq, void *offset)
} }
if (batman_count == 0) if (batman_count == 0)
seq_printf(seq, "No batman nodes in range ...\n"); seq_puts(seq, "No batman nodes in range ...\n");
out: out:
if (primary_if) if (primary_if)
......
...@@ -308,7 +308,7 @@ struct batadv_coded_packet { ...@@ -308,7 +308,7 @@ struct batadv_coded_packet {
uint8_t second_source[ETH_ALEN]; uint8_t second_source[ETH_ALEN];
uint8_t second_orig_dest[ETH_ALEN]; uint8_t second_orig_dest[ETH_ALEN];
__be32 second_crc; __be32 second_crc;
uint16_t coded_len; __be16 coded_len;
}; };
#endif /* _NET_BATMAN_ADV_PACKET_H_ */ #endif /* _NET_BATMAN_ADV_PACKET_H_ */
...@@ -401,55 +401,6 @@ static void batadv_set_lockdep_class(struct net_device *dev) ...@@ -401,55 +401,6 @@ static void batadv_set_lockdep_class(struct net_device *dev)
netdev_for_each_tx_queue(dev, batadv_set_lockdep_class_one, NULL); netdev_for_each_tx_queue(dev, batadv_set_lockdep_class_one, NULL);
} }
/**
* batadv_softif_init - Late stage initialization of soft interface
* @dev: registered network device to modify
*
* Returns error code on failures
*/
static int batadv_softif_init(struct net_device *dev)
{
batadv_set_lockdep_class(dev);
return 0;
}
static const struct net_device_ops batadv_netdev_ops = {
.ndo_init = batadv_softif_init,
.ndo_open = batadv_interface_open,
.ndo_stop = batadv_interface_release,
.ndo_get_stats = batadv_interface_stats,
.ndo_set_mac_address = batadv_interface_set_mac_addr,
.ndo_change_mtu = batadv_interface_change_mtu,
.ndo_start_xmit = batadv_interface_tx,
.ndo_validate_addr = eth_validate_addr
};
static void batadv_interface_setup(struct net_device *dev)
{
struct batadv_priv *priv = netdev_priv(dev);
ether_setup(dev);
dev->netdev_ops = &batadv_netdev_ops;
dev->destructor = free_netdev;
dev->tx_queue_len = 0;
/* can't call min_mtu, because the needed variables
* have not been initialized yet
*/
dev->mtu = ETH_DATA_LEN;
/* reserve more space in the skbuff for our header */
dev->hard_header_len = BATADV_HEADER_LEN;
/* generate random address */
eth_hw_addr_random(dev);
SET_ETHTOOL_OPS(dev, &batadv_ethtool_ops);
memset(priv, 0, sizeof(*priv));
}
/** /**
* batadv_softif_destroy_finish - cleans up the remains of a softif * batadv_softif_destroy_finish - cleans up the remains of a softif
* @work: work queue item * @work: work queue item
...@@ -466,7 +417,6 @@ static void batadv_softif_destroy_finish(struct work_struct *work) ...@@ -466,7 +417,6 @@ static void batadv_softif_destroy_finish(struct work_struct *work)
cleanup_work); cleanup_work);
soft_iface = bat_priv->soft_iface; soft_iface = bat_priv->soft_iface;
batadv_debugfs_del_meshif(soft_iface);
batadv_sysfs_del_meshif(soft_iface); batadv_sysfs_del_meshif(soft_iface);
rtnl_lock(); rtnl_lock();
...@@ -474,21 +424,22 @@ static void batadv_softif_destroy_finish(struct work_struct *work) ...@@ -474,21 +424,22 @@ static void batadv_softif_destroy_finish(struct work_struct *work)
rtnl_unlock(); rtnl_unlock();
} }
struct net_device *batadv_softif_create(const char *name) /**
* batadv_softif_init_late - late stage initialization of soft interface
* @dev: registered network device to modify
*
* Returns error code on failures
*/
static int batadv_softif_init_late(struct net_device *dev)
{ {
struct net_device *soft_iface;
struct batadv_priv *bat_priv; struct batadv_priv *bat_priv;
int ret; int ret;
size_t cnt_len = sizeof(uint64_t) * BATADV_CNT_NUM; size_t cnt_len = sizeof(uint64_t) * BATADV_CNT_NUM;
soft_iface = alloc_netdev(sizeof(*bat_priv), name, batadv_set_lockdep_class(dev);
batadv_interface_setup);
if (!soft_iface)
goto out;
bat_priv = netdev_priv(soft_iface); bat_priv = netdev_priv(dev);
bat_priv->soft_iface = soft_iface; bat_priv->soft_iface = dev;
INIT_WORK(&bat_priv->cleanup_work, batadv_softif_destroy_finish); INIT_WORK(&bat_priv->cleanup_work, batadv_softif_destroy_finish);
/* batadv_interface_stats() needs to be available as soon as /* batadv_interface_stats() needs to be available as soon as
...@@ -496,14 +447,7 @@ struct net_device *batadv_softif_create(const char *name) ...@@ -496,14 +447,7 @@ struct net_device *batadv_softif_create(const char *name)
*/ */
bat_priv->bat_counters = __alloc_percpu(cnt_len, __alignof__(uint64_t)); bat_priv->bat_counters = __alloc_percpu(cnt_len, __alignof__(uint64_t));
if (!bat_priv->bat_counters) if (!bat_priv->bat_counters)
goto free_soft_iface; return -ENOMEM;
ret = register_netdevice(soft_iface);
if (ret < 0) {
pr_err("Unable to register the batman interface '%s': %i\n",
name, ret);
goto free_bat_counters;
}
atomic_set(&bat_priv->aggregated_ogms, 1); atomic_set(&bat_priv->aggregated_ogms, 1);
atomic_set(&bat_priv->bonding, 0); atomic_set(&bat_priv->bonding, 0);
...@@ -541,51 +485,189 @@ struct net_device *batadv_softif_create(const char *name) ...@@ -541,51 +485,189 @@ struct net_device *batadv_softif_create(const char *name)
bat_priv->primary_if = NULL; bat_priv->primary_if = NULL;
bat_priv->num_ifaces = 0; bat_priv->num_ifaces = 0;
ret = batadv_algo_select(bat_priv, batadv_routing_algo);
if (ret < 0)
goto unreg_soft_iface;
batadv_nc_init_bat_priv(bat_priv); batadv_nc_init_bat_priv(bat_priv);
ret = batadv_sysfs_add_meshif(soft_iface); ret = batadv_algo_select(bat_priv, batadv_routing_algo);
if (ret < 0) if (ret < 0)
goto unreg_soft_iface; goto free_bat_counters;
ret = batadv_debugfs_add_meshif(soft_iface); ret = batadv_debugfs_add_meshif(dev);
if (ret < 0) if (ret < 0)
goto unreg_sysfs; goto free_bat_counters;
ret = batadv_mesh_init(soft_iface); ret = batadv_mesh_init(dev);
if (ret < 0) if (ret < 0)
goto unreg_debugfs; goto unreg_debugfs;
return soft_iface; return 0;
unreg_debugfs: unreg_debugfs:
batadv_debugfs_del_meshif(soft_iface); batadv_debugfs_del_meshif(dev);
unreg_sysfs:
batadv_sysfs_del_meshif(soft_iface);
unreg_soft_iface:
free_percpu(bat_priv->bat_counters);
unregister_netdevice(soft_iface);
return NULL;
free_bat_counters: free_bat_counters:
free_percpu(bat_priv->bat_counters); free_percpu(bat_priv->bat_counters);
free_soft_iface:
free_netdev(soft_iface); return ret;
}
/**
* batadv_softif_slave_add - Add a slave interface to a batadv_soft_interface
* @dev: batadv_soft_interface used as master interface
* @slave_dev: net_device which should become the slave interface
*
* Return 0 if successful or error otherwise.
*/
static int batadv_softif_slave_add(struct net_device *dev,
struct net_device *slave_dev)
{
struct batadv_hard_iface *hard_iface;
int ret = -EINVAL;
hard_iface = batadv_hardif_get_by_netdev(slave_dev);
if (!hard_iface || hard_iface->soft_iface != NULL)
goto out;
ret = batadv_hardif_enable_interface(hard_iface, dev->name);
out: out:
return NULL; if (hard_iface)
batadv_hardif_free_ref(hard_iface);
return ret;
}
/**
* batadv_softif_slave_del - Delete a slave iface from a batadv_soft_interface
* @dev: batadv_soft_interface used as master interface
* @slave_dev: net_device which should be removed from the master interface
*
* Return 0 if successful or error otherwise.
*/
static int batadv_softif_slave_del(struct net_device *dev,
struct net_device *slave_dev)
{
struct batadv_hard_iface *hard_iface;
int ret = -EINVAL;
hard_iface = batadv_hardif_get_by_netdev(slave_dev);
if (!hard_iface || hard_iface->soft_iface != dev)
goto out;
batadv_hardif_disable_interface(hard_iface, BATADV_IF_CLEANUP_KEEP);
ret = 0;
out:
if (hard_iface)
batadv_hardif_free_ref(hard_iface);
return ret;
}
static const struct net_device_ops batadv_netdev_ops = {
.ndo_init = batadv_softif_init_late,
.ndo_open = batadv_interface_open,
.ndo_stop = batadv_interface_release,
.ndo_get_stats = batadv_interface_stats,
.ndo_set_mac_address = batadv_interface_set_mac_addr,
.ndo_change_mtu = batadv_interface_change_mtu,
.ndo_start_xmit = batadv_interface_tx,
.ndo_validate_addr = eth_validate_addr,
.ndo_add_slave = batadv_softif_slave_add,
.ndo_del_slave = batadv_softif_slave_del,
};
/**
* batadv_softif_free - Deconstructor of batadv_soft_interface
* @dev: Device to cleanup and remove
*/
static void batadv_softif_free(struct net_device *dev)
{
batadv_debugfs_del_meshif(dev);
batadv_mesh_free(dev);
free_netdev(dev);
} }
void batadv_softif_destroy(struct net_device *soft_iface) /**
* batadv_softif_init_early - early stage initialization of soft interface
* @dev: registered network device to modify
*/
static void batadv_softif_init_early(struct net_device *dev)
{
struct batadv_priv *priv = netdev_priv(dev);
ether_setup(dev);
dev->netdev_ops = &batadv_netdev_ops;
dev->destructor = batadv_softif_free;
dev->tx_queue_len = 0;
/* can't call min_mtu, because the needed variables
* have not been initialized yet
*/
dev->mtu = ETH_DATA_LEN;
/* reserve more space in the skbuff for our header */
dev->hard_header_len = BATADV_HEADER_LEN;
/* generate random address */
eth_hw_addr_random(dev);
SET_ETHTOOL_OPS(dev, &batadv_ethtool_ops);
memset(priv, 0, sizeof(*priv));
}
struct net_device *batadv_softif_create(const char *name)
{
struct net_device *soft_iface;
int ret;
soft_iface = alloc_netdev(sizeof(struct batadv_priv), name,
batadv_softif_init_early);
if (!soft_iface)
return NULL;
soft_iface->rtnl_link_ops = &batadv_link_ops;
ret = register_netdevice(soft_iface);
if (ret < 0) {
pr_err("Unable to register the batman interface '%s': %i\n",
name, ret);
free_netdev(soft_iface);
return NULL;
}
return soft_iface;
}
/**
* batadv_softif_destroy_sysfs - deletion of batadv_soft_interface via sysfs
* @soft_iface: the to-be-removed batman-adv interface
*/
void batadv_softif_destroy_sysfs(struct net_device *soft_iface)
{ {
struct batadv_priv *bat_priv = netdev_priv(soft_iface); struct batadv_priv *bat_priv = netdev_priv(soft_iface);
batadv_mesh_free(soft_iface);
queue_work(batadv_event_workqueue, &bat_priv->cleanup_work); queue_work(batadv_event_workqueue, &bat_priv->cleanup_work);
} }
/**
* batadv_softif_destroy_netlink - deletion of batadv_soft_interface via netlink
* @soft_iface: the to-be-removed batman-adv interface
* @head: list pointer
*/
static void batadv_softif_destroy_netlink(struct net_device *soft_iface,
struct list_head *head)
{
struct batadv_hard_iface *hard_iface;
list_for_each_entry(hard_iface, &batadv_hardif_list, list) {
if (hard_iface->soft_iface == soft_iface)
batadv_hardif_disable_interface(hard_iface,
BATADV_IF_CLEANUP_KEEP);
}
batadv_sysfs_del_meshif(soft_iface);
unregister_netdevice_queue(soft_iface, head);
}
int batadv_softif_is_valid(const struct net_device *net_dev) int batadv_softif_is_valid(const struct net_device *net_dev)
{ {
if (net_dev->netdev_ops->ndo_start_xmit == batadv_interface_tx) if (net_dev->netdev_ops->ndo_start_xmit == batadv_interface_tx)
...@@ -594,6 +676,13 @@ int batadv_softif_is_valid(const struct net_device *net_dev) ...@@ -594,6 +676,13 @@ int batadv_softif_is_valid(const struct net_device *net_dev)
return 0; return 0;
} }
struct rtnl_link_ops batadv_link_ops __read_mostly = {
.kind = "batadv",
.priv_size = sizeof(struct batadv_priv),
.setup = batadv_softif_init_early,
.dellink = batadv_softif_destroy_netlink,
};
/* ethtool */ /* ethtool */
static int batadv_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int batadv_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{ {
......
...@@ -25,7 +25,8 @@ void batadv_interface_rx(struct net_device *soft_iface, ...@@ -25,7 +25,8 @@ void batadv_interface_rx(struct net_device *soft_iface,
struct sk_buff *skb, struct batadv_hard_iface *recv_if, struct sk_buff *skb, struct batadv_hard_iface *recv_if,
int hdr_size, struct batadv_orig_node *orig_node); int hdr_size, struct batadv_orig_node *orig_node);
struct net_device *batadv_softif_create(const char *name); struct net_device *batadv_softif_create(const char *name);
void batadv_softif_destroy(struct net_device *soft_iface); void batadv_softif_destroy_sysfs(struct net_device *soft_iface);
int batadv_softif_is_valid(const struct net_device *net_dev); int batadv_softif_is_valid(const struct net_device *net_dev);
extern struct rtnl_link_ops batadv_link_ops;
#endif /* _NET_BATMAN_ADV_SOFT_INTERFACE_H_ */ #endif /* _NET_BATMAN_ADV_SOFT_INTERFACE_H_ */
...@@ -588,13 +588,15 @@ static ssize_t batadv_store_mesh_iface(struct kobject *kobj, ...@@ -588,13 +588,15 @@ static ssize_t batadv_store_mesh_iface(struct kobject *kobj,
} }
if (status_tmp == BATADV_IF_NOT_IN_USE) { if (status_tmp == BATADV_IF_NOT_IN_USE) {
batadv_hardif_disable_interface(hard_iface); batadv_hardif_disable_interface(hard_iface,
BATADV_IF_CLEANUP_AUTO);
goto unlock; goto unlock;
} }
/* if the interface already is in use */ /* if the interface already is in use */
if (hard_iface->if_status != BATADV_IF_NOT_IN_USE) if (hard_iface->if_status != BATADV_IF_NOT_IN_USE)
batadv_hardif_disable_interface(hard_iface); batadv_hardif_disable_interface(hard_iface,
BATADV_IF_CLEANUP_AUTO);
ret = batadv_hardif_enable_interface(hard_iface, buff); ret = batadv_hardif_enable_interface(hard_iface, buff);
......
...@@ -149,7 +149,7 @@ static void batadv_vis_data_read_prim_sec(struct seq_file *seq, ...@@ -149,7 +149,7 @@ static void batadv_vis_data_read_prim_sec(struct seq_file *seq,
hlist_for_each_entry(entry, if_list, list) { hlist_for_each_entry(entry, if_list, list) {
if (entry->primary) if (entry->primary)
seq_printf(seq, "PRIMARY, "); seq_puts(seq, "PRIMARY, ");
else else
seq_printf(seq, "SEC %pM, ", entry->addr); seq_printf(seq, "SEC %pM, ", entry->addr);
} }
...@@ -207,7 +207,7 @@ static void batadv_vis_data_read_entries(struct seq_file *seq, ...@@ -207,7 +207,7 @@ static void batadv_vis_data_read_entries(struct seq_file *seq,
if (batadv_compare_eth(entry->addr, packet->vis_orig)) if (batadv_compare_eth(entry->addr, packet->vis_orig))
batadv_vis_data_read_prim_sec(seq, list); batadv_vis_data_read_prim_sec(seq, list);
seq_printf(seq, "\n"); seq_puts(seq, "\n");
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment