|
@@ -439,6 +439,13 @@ int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb,
|
|
BATADV_P_DATA, orig_node, vid);
|
|
BATADV_P_DATA, orig_node, vid);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * batadv_forw_packet_free - free a forwarding packet
|
|
|
|
+ * @forw_packet: The packet to free
|
|
|
|
+ *
|
|
|
|
+ * This frees a forwarding packet and releases any resources it might
|
|
|
|
+ * have claimed.
|
|
|
|
+ */
|
|
void batadv_forw_packet_free(struct batadv_forw_packet *forw_packet)
|
|
void batadv_forw_packet_free(struct batadv_forw_packet *forw_packet)
|
|
{
|
|
{
|
|
kfree_skb(forw_packet->skb);
|
|
kfree_skb(forw_packet->skb);
|
|
@@ -446,9 +453,73 @@ void batadv_forw_packet_free(struct batadv_forw_packet *forw_packet)
|
|
batadv_hardif_put(forw_packet->if_incoming);
|
|
batadv_hardif_put(forw_packet->if_incoming);
|
|
if (forw_packet->if_outgoing)
|
|
if (forw_packet->if_outgoing)
|
|
batadv_hardif_put(forw_packet->if_outgoing);
|
|
batadv_hardif_put(forw_packet->if_outgoing);
|
|
|
|
+ if (forw_packet->queue_left)
|
|
|
|
+ atomic_inc(forw_packet->queue_left);
|
|
kfree(forw_packet);
|
|
kfree(forw_packet);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * batadv_forw_packet_alloc - allocate a forwarding packet
|
|
|
|
+ * @if_incoming: The (optional) if_incoming to be grabbed
|
|
|
|
+ * @if_outgoing: The (optional) if_outgoing to be grabbed
|
|
|
|
+ * @queue_left: The (optional) queue counter to decrease
|
|
|
|
+ * @bat_priv: The bat_priv for the mesh of this forw_packet
|
|
|
|
+ *
|
|
|
|
+ * Allocates a forwarding packet and tries to get a reference to the
|
|
|
|
+ * (optional) if_incoming, if_outgoing and queue_left. If queue_left
|
|
|
|
+ * is NULL then bat_priv is optional, too.
|
|
|
|
+ *
|
|
|
|
+ * Return: An allocated forwarding packet on success, NULL otherwise.
|
|
|
|
+ */
|
|
|
|
+struct batadv_forw_packet *
|
|
|
|
+batadv_forw_packet_alloc(struct batadv_hard_iface *if_incoming,
|
|
|
|
+ struct batadv_hard_iface *if_outgoing,
|
|
|
|
+ atomic_t *queue_left,
|
|
|
|
+ struct batadv_priv *bat_priv)
|
|
|
|
+{
|
|
|
|
+ struct batadv_forw_packet *forw_packet;
|
|
|
|
+ const char *qname;
|
|
|
|
+
|
|
|
|
+ if (queue_left && !batadv_atomic_dec_not_zero(queue_left)) {
|
|
|
|
+ qname = "unknown";
|
|
|
|
+
|
|
|
|
+ if (queue_left == &bat_priv->bcast_queue_left)
|
|
|
|
+ qname = "bcast";
|
|
|
|
+
|
|
|
|
+ if (queue_left == &bat_priv->batman_queue_left)
|
|
|
|
+ qname = "batman";
|
|
|
|
+
|
|
|
|
+ batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
|
|
|
|
+ "%s queue is full\n", qname);
|
|
|
|
+
|
|
|
|
+ return NULL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ forw_packet = kmalloc(sizeof(*forw_packet), GFP_ATOMIC);
|
|
|
|
+ if (!forw_packet)
|
|
|
|
+ goto err;
|
|
|
|
+
|
|
|
|
+ if (if_incoming)
|
|
|
|
+ kref_get(&if_incoming->refcount);
|
|
|
|
+
|
|
|
|
+ if (if_outgoing)
|
|
|
|
+ kref_get(&if_outgoing->refcount);
|
|
|
|
+
|
|
|
|
+ forw_packet->skb = NULL;
|
|
|
|
+ forw_packet->queue_left = queue_left;
|
|
|
|
+ forw_packet->if_incoming = if_incoming;
|
|
|
|
+ forw_packet->if_outgoing = if_outgoing;
|
|
|
|
+ forw_packet->num_packets = 0;
|
|
|
|
+
|
|
|
|
+ return forw_packet;
|
|
|
|
+
|
|
|
|
+err:
|
|
|
|
+ if (queue_left)
|
|
|
|
+ atomic_inc(queue_left);
|
|
|
|
+
|
|
|
|
+ return NULL;
|
|
|
|
+}
|
|
|
|
+
|
|
static void
|
|
static void
|
|
_batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv,
|
|
_batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv,
|
|
struct batadv_forw_packet *forw_packet,
|
|
struct batadv_forw_packet *forw_packet,
|
|
@@ -487,24 +558,20 @@ int batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv,
|
|
struct batadv_bcast_packet *bcast_packet;
|
|
struct batadv_bcast_packet *bcast_packet;
|
|
struct sk_buff *newskb;
|
|
struct sk_buff *newskb;
|
|
|
|
|
|
- if (!batadv_atomic_dec_not_zero(&bat_priv->bcast_queue_left)) {
|
|
|
|
- batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
|
|
|
|
- "bcast packet queue full\n");
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
primary_if = batadv_primary_if_get_selected(bat_priv);
|
|
primary_if = batadv_primary_if_get_selected(bat_priv);
|
|
if (!primary_if)
|
|
if (!primary_if)
|
|
- goto out_and_inc;
|
|
|
|
-
|
|
|
|
- forw_packet = kmalloc(sizeof(*forw_packet), GFP_ATOMIC);
|
|
|
|
|
|
+ goto err;
|
|
|
|
|
|
|
|
+ forw_packet = batadv_forw_packet_alloc(primary_if, NULL,
|
|
|
|
+ &bat_priv->bcast_queue_left,
|
|
|
|
+ bat_priv);
|
|
|
|
+ batadv_hardif_put(primary_if);
|
|
if (!forw_packet)
|
|
if (!forw_packet)
|
|
- goto out_and_inc;
|
|
|
|
|
|
+ goto err;
|
|
|
|
|
|
newskb = skb_copy(skb, GFP_ATOMIC);
|
|
newskb = skb_copy(skb, GFP_ATOMIC);
|
|
if (!newskb)
|
|
if (!newskb)
|
|
- goto packet_free;
|
|
|
|
|
|
+ goto err_packet_free;
|
|
|
|
|
|
/* as we have a copy now, it is safe to decrease the TTL */
|
|
/* as we have a copy now, it is safe to decrease the TTL */
|
|
bcast_packet = (struct batadv_bcast_packet *)newskb->data;
|
|
bcast_packet = (struct batadv_bcast_packet *)newskb->data;
|
|
@@ -513,11 +580,6 @@ int batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv,
|
|
skb_reset_mac_header(newskb);
|
|
skb_reset_mac_header(newskb);
|
|
|
|
|
|
forw_packet->skb = newskb;
|
|
forw_packet->skb = newskb;
|
|
- forw_packet->if_incoming = primary_if;
|
|
|
|
- forw_packet->if_outgoing = NULL;
|
|
|
|
-
|
|
|
|
- /* how often did we send the bcast packet ? */
|
|
|
|
- forw_packet->num_packets = 0;
|
|
|
|
|
|
|
|
INIT_DELAYED_WORK(&forw_packet->delayed_work,
|
|
INIT_DELAYED_WORK(&forw_packet->delayed_work,
|
|
batadv_send_outstanding_bcast_packet);
|
|
batadv_send_outstanding_bcast_packet);
|
|
@@ -525,13 +587,9 @@ int batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv,
|
|
_batadv_add_bcast_packet_to_list(bat_priv, forw_packet, delay);
|
|
_batadv_add_bcast_packet_to_list(bat_priv, forw_packet, delay);
|
|
return NETDEV_TX_OK;
|
|
return NETDEV_TX_OK;
|
|
|
|
|
|
-packet_free:
|
|
|
|
- kfree(forw_packet);
|
|
|
|
-out_and_inc:
|
|
|
|
- atomic_inc(&bat_priv->bcast_queue_left);
|
|
|
|
-out:
|
|
|
|
- if (primary_if)
|
|
|
|
- batadv_hardif_put(primary_if);
|
|
|
|
|
|
+err_packet_free:
|
|
|
|
+ batadv_forw_packet_free(forw_packet);
|
|
|
|
+err:
|
|
return NETDEV_TX_BUSY;
|
|
return NETDEV_TX_BUSY;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -592,7 +650,6 @@ static void batadv_send_outstanding_bcast_packet(struct work_struct *work)
|
|
|
|
|
|
out:
|
|
out:
|
|
batadv_forw_packet_free(forw_packet);
|
|
batadv_forw_packet_free(forw_packet);
|
|
- atomic_inc(&bat_priv->bcast_queue_left);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
void
|
|
@@ -633,9 +690,6 @@ batadv_purge_outstanding_packets(struct batadv_priv *bat_priv,
|
|
|
|
|
|
if (pending) {
|
|
if (pending) {
|
|
hlist_del(&forw_packet->list);
|
|
hlist_del(&forw_packet->list);
|
|
- if (!forw_packet->own)
|
|
|
|
- atomic_inc(&bat_priv->bcast_queue_left);
|
|
|
|
-
|
|
|
|
batadv_forw_packet_free(forw_packet);
|
|
batadv_forw_packet_free(forw_packet);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -663,9 +717,6 @@ batadv_purge_outstanding_packets(struct batadv_priv *bat_priv,
|
|
|
|
|
|
if (pending) {
|
|
if (pending) {
|
|
hlist_del(&forw_packet->list);
|
|
hlist_del(&forw_packet->list);
|
|
- if (!forw_packet->own)
|
|
|
|
- atomic_inc(&bat_priv->batman_queue_left);
|
|
|
|
-
|
|
|
|
batadv_forw_packet_free(forw_packet);
|
|
batadv_forw_packet_free(forw_packet);
|
|
}
|
|
}
|
|
}
|
|
}
|