summaryrefslogtreecommitdiffstats
path: root/drivers/staging/batman-adv/soft-interface.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/batman-adv/soft-interface.c')
-rw-r--r--drivers/staging/batman-adv/soft-interface.c241
1 files changed, 136 insertions, 105 deletions
diff --git a/drivers/staging/batman-adv/soft-interface.c b/drivers/staging/batman-adv/soft-interface.c
index 2ea97de..3904db9 100644
--- a/drivers/staging/batman-adv/soft-interface.c
+++ b/drivers/staging/batman-adv/soft-interface.c
@@ -24,19 +24,18 @@
#include "hard-interface.h"
#include "routing.h"
#include "send.h"
+#include "bat_debugfs.h"
#include "translation-table.h"
#include "types.h"
#include "hash.h"
+#include "send.h"
+#include "bat_sysfs.h"
#include <linux/slab.h>
#include <linux/ethtool.h>
#include <linux/etherdevice.h>
+#include "unicast.h"
-static uint32_t bcast_seqno = 1; /* give own bcast messages seq numbers to avoid
- * broadcast storms */
-static int32_t skb_packets;
-static int32_t skb_bad_packets;
-unsigned char main_if_addr[ETH_ALEN];
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);
@@ -56,23 +55,21 @@ static const struct ethtool_ops bat_ethtool_ops = {
.set_rx_csum = bat_set_rx_csum
};
-void set_main_if_addr(uint8_t *addr)
-{
- memcpy(main_if_addr, addr, ETH_ALEN);
-}
-
-int my_skb_push(struct sk_buff *skb, unsigned int len)
+int my_skb_head_push(struct sk_buff *skb, unsigned int len)
{
- int result = 0;
-
- skb_packets++;
- if (skb_headroom(skb) < len) {
- skb_bad_packets++;
- result = pskb_expand_head(skb, len, 0, GFP_ATOMIC);
-
- if (result < 0)
- return result;
- }
+ int result;
+
+ /**
+ * TODO: We must check if we can release all references to non-payload
+ * 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;
@@ -92,21 +89,23 @@ static int interface_release(struct net_device *dev)
static struct net_device_stats *interface_stats(struct net_device *dev)
{
- struct bat_priv *priv = netdev_priv(dev);
- return &priv->stats;
+ 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;
/* only modify hna-table if it has been initialised before */
- if (atomic_read(&module_state) == MODULE_ACTIVE) {
- hna_local_remove(dev->dev_addr, "mac address changed");
- hna_local_add(addr->sa_data);
+ if (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) {
+ hna_local_remove(bat_priv, dev->dev_addr,
+ "mac address changed");
+ hna_local_add(dev, addr->sa_data);
}
memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
@@ -117,7 +116,7 @@ static int interface_set_mac_addr(struct net_device *dev, void *p)
static int interface_change_mtu(struct net_device *dev, int new_mtu)
{
/* check ranges */
- if ((new_mtu < 68) || (new_mtu > hardif_min_mtu()))
+ if ((new_mtu < 68) || (new_mtu > hardif_min_mtu(dev)))
return -EINVAL;
dev->mtu = new_mtu;
@@ -125,34 +124,27 @@ static int interface_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
-int interface_tx(struct sk_buff *skb, struct net_device *dev)
+int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
{
- struct unicast_packet *unicast_packet;
- struct bcast_packet *bcast_packet;
- struct orig_node *orig_node;
- struct neigh_node *router;
struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
- struct bat_priv *priv = netdev_priv(dev);
- struct batman_if *batman_if;
- struct bat_priv *bat_priv;
- uint8_t dstaddr[6];
- int data_len = skb->len;
- unsigned long flags;
+ struct bat_priv *bat_priv = netdev_priv(soft_iface);
+ struct bcast_packet *bcast_packet;
+ int data_len = skb->len, ret;
- if (atomic_read(&module_state) != MODULE_ACTIVE)
+ if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
goto dropped;
- /* FIXME: each batman_if will be attached to a softif */
- bat_priv = netdev_priv(soft_device);
+ soft_iface->trans_start = jiffies;
- dev->trans_start = jiffies;
/* TODO: check this for locks */
- hna_local_add(ethhdr->h_source);
+ hna_local_add(soft_iface, ethhdr->h_source);
/* ethernet packet should be broadcasted */
if (is_bcast(ethhdr->h_dest) || is_mcast(ethhdr->h_dest)) {
+ if (!bat_priv->primary_if)
+ goto dropped;
- if (my_skb_push(skb, sizeof(struct bcast_packet)) < 0)
+ if (my_skb_head_push(skb, sizeof(struct bcast_packet)) < 0)
goto dropped;
bcast_packet = (struct bcast_packet *)skb->data;
@@ -164,14 +156,14 @@ int interface_tx(struct sk_buff *skb, struct net_device *dev)
/* hw address of first interface is the orig mac because only
* this mac is known throughout the mesh */
- memcpy(bcast_packet->orig, main_if_addr, ETH_ALEN);
+ memcpy(bcast_packet->orig,
+ bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
/* set broadcast sequence number */
- bcast_packet->seqno = htonl(bcast_seqno);
+ bcast_packet->seqno =
+ htonl(atomic_inc_return(&bat_priv->bcast_seqno));
- /* broadcast packet. on success, increase seqno. */
- if (add_bcast_packet_to_list(skb) == NETDEV_TX_OK)
- bcast_seqno++;
+ add_bcast_packet_to_list(bat_priv, skb);
/* a copy is stored in the bcast list, therefore removing
* the original skb. */
@@ -179,64 +171,27 @@ int interface_tx(struct sk_buff *skb, struct net_device *dev)
/* unicast packet */
} else {
- spin_lock_irqsave(&orig_hash_lock, flags);
- /* get routing information */
- orig_node = ((struct orig_node *)hash_find(orig_hash,
- ethhdr->h_dest));
-
- /* check for hna host */
- if (!orig_node)
- orig_node = transtable_search(ethhdr->h_dest);
-
- router = find_router(orig_node, NULL);
-
- if (!router)
- goto unlock;
-
- /* don't lock while sending the packets ... we therefore
- * copy the required data before sending */
-
- batman_if = router->if_incoming;
- memcpy(dstaddr, router->addr, ETH_ALEN);
-
- spin_unlock_irqrestore(&orig_hash_lock, flags);
-
- if (batman_if->if_status != IF_ACTIVE)
- goto dropped;
-
- if (my_skb_push(skb, sizeof(struct unicast_packet)) < 0)
- goto dropped;
-
- unicast_packet = (struct unicast_packet *)skb->data;
-
- unicast_packet->version = COMPAT_VERSION;
- /* batman packet type: unicast */
- unicast_packet->packet_type = BAT_UNICAST;
- /* set unicast ttl */
- unicast_packet->ttl = TTL;
- /* copy the destination for faster routing */
- memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN);
-
- send_skb_packet(skb, batman_if, dstaddr);
+ ret = unicast_send_skb(skb, bat_priv);
+ if (ret != 0)
+ goto dropped_freed;
}
- priv->stats.tx_packets++;
- priv->stats.tx_bytes += data_len;
+ bat_priv->stats.tx_packets++;
+ bat_priv->stats.tx_bytes += data_len;
goto end;
-unlock:
- spin_unlock_irqrestore(&orig_hash_lock, flags);
dropped:
- priv->stats.tx_dropped++;
kfree_skb(skb);
+dropped_freed:
+ bat_priv->stats.tx_dropped++;
end:
return NETDEV_TX_OK;
}
-void interface_rx(struct sk_buff *skb, int hdr_size)
+void interface_rx(struct net_device *soft_iface,
+ struct sk_buff *skb, int hdr_size)
{
- struct net_device *dev = soft_device;
- struct bat_priv *priv = netdev_priv(dev);
+ struct bat_priv *priv = netdev_priv(soft_iface);
/* check if enough space is available for pulling, and pull */
if (!pskb_may_pull(skb, hdr_size)) {
@@ -246,8 +201,8 @@ void interface_rx(struct sk_buff *skb, int hdr_size)
skb_pull_rcsum(skb, hdr_size);
/* skb_set_mac_header(skb, -sizeof(struct ethhdr));*/
- skb->dev = dev;
- skb->protocol = eth_type_trans(skb, dev);
+ /* skb->dev & skb->pkt_type are set here */
+ skb->protocol = eth_type_trans(skb, soft_iface);
/* should not be neccesary anymore as we use skb_pull_rcsum()
* TODO: please verify this and remove this TODO
@@ -255,13 +210,10 @@ void interface_rx(struct sk_buff *skb, int hdr_size)
/* skb->ip_summed = CHECKSUM_UNNECESSARY;*/
- /* TODO: set skb->pkt_type to PACKET_BROADCAST, PACKET_MULTICAST,
- * PACKET_OTHERHOST or PACKET_HOST */
-
priv->stats.rx_packets++;
- priv->stats.rx_bytes += skb->len;
+ priv->stats.rx_bytes += skb->len + sizeof(struct ethhdr);
- dev->last_rx = jiffies;
+ soft_iface->last_rx = jiffies;
netif_rx(skb);
}
@@ -278,7 +230,7 @@ static const struct net_device_ops bat_netdev_ops = {
};
#endif
-void interface_setup(struct net_device *dev)
+static void interface_setup(struct net_device *dev)
{
struct bat_priv *priv = netdev_priv(dev);
char dev_addr[ETH_ALEN];
@@ -297,7 +249,11 @@ void interface_setup(struct net_device *dev)
#endif
dev->destructor = free_netdev;
- dev->mtu = hardif_min_mtu();
+ /**
+ * can't call min_mtu, because the needed variables
+ * have not been initialized yet
+ */
+ dev->mtu = ETH_DATA_LEN;
dev->hard_header_len = BAT_HEADER_LEN; /* reserve more space in the
* skbuff for our header */
@@ -310,6 +266,81 @@ void interface_setup(struct net_device *dev)
memset(priv, 0, sizeof(struct bat_priv));
}
+struct net_device *softif_create(char *name)
+{
+ struct net_device *soft_iface;
+ struct bat_priv *bat_priv;
+ int ret;
+
+ soft_iface = alloc_netdev(sizeof(struct bat_priv) , name,
+ interface_setup);
+
+ if (!soft_iface) {
+ pr_err("Unable to allocate the batman interface: %s\n", name);
+ goto out;
+ }
+
+ ret = register_netdev(soft_iface);
+ 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->aggregation_enabled, 1);
+ atomic_set(&bat_priv->bonding_enabled, 0);
+ atomic_set(&bat_priv->vis_mode, VIS_TYPE_CLIENT_UPDATE);
+ atomic_set(&bat_priv->orig_interval, 1000);
+ atomic_set(&bat_priv->log_level, 0);
+ atomic_set(&bat_priv->frag_enabled, 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);
+ atomic_set(&bat_priv->hna_local_changed, 0);
+
+ bat_priv->primary_if = NULL;
+ bat_priv->num_ifaces = 0;
+
+ ret = sysfs_add_meshif(soft_iface);
+ if (ret < 0)
+ goto unreg_soft_iface;
+
+ ret = debugfs_add_meshif(soft_iface);
+ if (ret < 0)
+ goto unreg_sysfs;
+
+ ret = mesh_init(soft_iface);
+ if (ret < 0)
+ goto unreg_debugfs;
+
+ return soft_iface;
+
+unreg_debugfs:
+ debugfs_del_meshif(soft_iface);
+unreg_sysfs:
+ sysfs_del_meshif(soft_iface);
+unreg_soft_iface:
+ unregister_netdev(soft_iface);
+ return NULL;
+
+free_soft_iface:
+ free_netdev(soft_iface);
+out:
+ return NULL;
+}
+
+void softif_destroy(struct net_device *soft_iface)
+{
+ debugfs_del_meshif(soft_iface);
+ sysfs_del_meshif(soft_iface);
+ mesh_free(soft_iface);
+ unregister_netdevice(soft_iface);
+}
+
/* ethtool */
static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
OpenPOWER on IntegriCloud