diff options
Diffstat (limited to 'drivers/staging/batman-adv/soft-interface.c')
-rw-r--r-- | drivers/staging/batman-adv/soft-interface.c | 241 |
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) { |