mirror of
https://github.com/torvalds/linux.git
synced 2026-05-28 17:13:52 +02:00
batman-adv: iv: recover OGM scheduling after forward packet error
When batadv_iv_ogm_schedule_buff() fails to allocate and queue a forward
packet for OGM transmission, the work item that drives periodic OGM
scheduling is never re-armed. This silently halts transmission of the
node's own OGMs on the affected interface — only OGMs from other peers
continue to be aggregated and forwarded.
Fix this by tracking whether batadv_iv_ogm_queue_add() (and transitively
batadv_iv_ogm_aggregate_new()) successfully scheduled a forward packet.
When scheduling fails, batadv_iv_ogm_schedule_buff() falls back to queuing
a dedicated recovery work item (reschedule_work) that fires after one
originator interval and calls batadv_iv_ogm_schedule() again.
Cc: stable@kernel.org
Fixes: c6c8fea297 ("net: Add batman-adv meshing protocol")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
This commit is contained in:
parent
20c2d6a20c
commit
aa3153bd13
|
|
@ -224,6 +224,8 @@ static void batadv_iv_ogm_iface_disable(struct batadv_hard_iface *hard_iface)
|
|||
hard_iface->bat_iv.ogm_buff = NULL;
|
||||
|
||||
mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex);
|
||||
|
||||
cancel_delayed_work_sync(&hard_iface->bat_iv.reschedule_work);
|
||||
}
|
||||
|
||||
static void batadv_iv_ogm_iface_update_mac(struct batadv_hard_iface *hard_iface)
|
||||
|
|
@ -536,8 +538,10 @@ batadv_iv_ogm_can_aggregate(const struct batadv_ogm_packet *new_bat_ogm_packet,
|
|||
* @if_incoming: interface where the packet was received
|
||||
* @if_outgoing: interface for which the retransmission should be considered
|
||||
* @own_packet: true if it is a self-generated ogm
|
||||
*
|
||||
* Return: whether forward packet was scheduled
|
||||
*/
|
||||
static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
|
||||
static bool batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
|
||||
int packet_len, unsigned long send_time,
|
||||
bool direct_link,
|
||||
struct batadv_hard_iface *if_incoming,
|
||||
|
|
@ -561,13 +565,13 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
|
|||
|
||||
skb = netdev_alloc_skb_ip_align(NULL, skb_size);
|
||||
if (!skb)
|
||||
return;
|
||||
return false;
|
||||
|
||||
forw_packet_aggr = batadv_forw_packet_alloc(if_incoming, if_outgoing,
|
||||
queue_left, bat_priv, skb);
|
||||
if (!forw_packet_aggr) {
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
forw_packet_aggr->skb->priority = TC_PRIO_CONTROL;
|
||||
|
|
@ -590,6 +594,8 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
|
|||
batadv_iv_send_outstanding_bat_ogm_packet);
|
||||
|
||||
batadv_forw_packet_ogmv1_queue(bat_priv, forw_packet_aggr, send_time);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* aggregate a new packet into the existing ogm packet */
|
||||
|
|
@ -617,8 +623,10 @@ static void batadv_iv_ogm_aggregate(struct batadv_forw_packet *forw_packet_aggr,
|
|||
* @if_outgoing: interface for which the retransmission should be considered
|
||||
* @own_packet: true if it is a self-generated ogm
|
||||
* @send_time: timestamp (jiffies) when the packet is to be sent
|
||||
*
|
||||
* Return: whether forward packet was scheduled
|
||||
*/
|
||||
static void batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv,
|
||||
static bool batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv,
|
||||
unsigned char *packet_buff,
|
||||
int packet_len,
|
||||
struct batadv_hard_iface *if_incoming,
|
||||
|
|
@ -670,14 +678,16 @@ static void batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv,
|
|||
if (!own_packet && atomic_read(&bat_priv->aggregated_ogms))
|
||||
send_time += max_aggregation_jiffies;
|
||||
|
||||
batadv_iv_ogm_aggregate_new(packet_buff, packet_len,
|
||||
send_time, direct_link,
|
||||
if_incoming, if_outgoing,
|
||||
own_packet);
|
||||
return batadv_iv_ogm_aggregate_new(packet_buff, packet_len,
|
||||
send_time, direct_link,
|
||||
if_incoming, if_outgoing,
|
||||
own_packet);
|
||||
} else {
|
||||
batadv_iv_ogm_aggregate(forw_packet_aggr, packet_buff,
|
||||
packet_len, direct_link);
|
||||
spin_unlock_bh(&bat_priv->forw_bat_list_lock);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -790,6 +800,8 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface)
|
|||
u32 seqno;
|
||||
u16 tvlv_len = 0;
|
||||
unsigned long send_time;
|
||||
bool reschedule = false;
|
||||
bool scheduled;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&hard_iface->bat_iv.ogm_buff_mutex);
|
||||
|
|
@ -818,11 +830,8 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface)
|
|||
ogm_buff_len,
|
||||
BATADV_OGM_HLEN);
|
||||
if (ret < 0) {
|
||||
/* OGMs must be queued even when the buffer allocation for
|
||||
* TVLVs failed. just fall back to the non-TVLV version
|
||||
*/
|
||||
ret = 0;
|
||||
*ogm_buff_len = BATADV_OGM_HLEN;
|
||||
reschedule = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
tvlv_len = ret;
|
||||
|
|
@ -844,8 +853,11 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface)
|
|||
/* OGMs from secondary interfaces are only scheduled on their
|
||||
* respective interfaces.
|
||||
*/
|
||||
batadv_iv_ogm_queue_add(bat_priv, *ogm_buff, *ogm_buff_len,
|
||||
hard_iface, hard_iface, 1, send_time);
|
||||
scheduled = batadv_iv_ogm_queue_add(bat_priv, *ogm_buff, *ogm_buff_len,
|
||||
hard_iface, hard_iface, 1, send_time);
|
||||
if (!scheduled)
|
||||
reschedule = true;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
@ -857,15 +869,28 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface)
|
|||
if (!kref_get_unless_zero(&tmp_hard_iface->refcount))
|
||||
continue;
|
||||
|
||||
batadv_iv_ogm_queue_add(bat_priv, *ogm_buff,
|
||||
*ogm_buff_len, hard_iface,
|
||||
tmp_hard_iface, 1, send_time);
|
||||
|
||||
scheduled = batadv_iv_ogm_queue_add(bat_priv, *ogm_buff,
|
||||
*ogm_buff_len, hard_iface,
|
||||
tmp_hard_iface, 1, send_time);
|
||||
batadv_hardif_put(tmp_hard_iface);
|
||||
|
||||
if (!scheduled && tmp_hard_iface == hard_iface)
|
||||
reschedule = true;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
out:
|
||||
if (reschedule) {
|
||||
/* there was a failure scheduling the own forward packet.
|
||||
* as result, the batadv_iv_send_outstanding_bat_ogm_packet()
|
||||
* work item is no longer scheduled. it is therefore necessary
|
||||
* to reschedule it manually
|
||||
*/
|
||||
queue_delayed_work(batadv_event_workqueue,
|
||||
&hard_iface->bat_iv.reschedule_work,
|
||||
msecs_to_jiffies(atomic_read(&bat_priv->orig_interval)));
|
||||
}
|
||||
|
||||
batadv_hardif_put(primary_if);
|
||||
}
|
||||
|
||||
|
|
@ -880,6 +905,17 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
|
|||
mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex);
|
||||
}
|
||||
|
||||
static void batadv_iv_ogm_reschedule(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *delayed_work = to_delayed_work(work);
|
||||
struct batadv_hard_iface *hard_iface;
|
||||
|
||||
hard_iface = container_of(delayed_work,
|
||||
struct batadv_hard_iface,
|
||||
bat_iv.reschedule_work);
|
||||
batadv_iv_ogm_schedule(hard_iface);
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_iv_orig_ifinfo_sum() - Get bcast_own sum for originator over interface
|
||||
* @orig_node: originator which reproadcasted the OGMs directly
|
||||
|
|
@ -2272,6 +2308,8 @@ batadv_iv_ogm_neigh_is_sob(struct batadv_neigh_node *neigh1,
|
|||
|
||||
static void batadv_iv_iface_enabled(struct batadv_hard_iface *hard_iface)
|
||||
{
|
||||
INIT_DELAYED_WORK(&hard_iface->bat_iv.reschedule_work, batadv_iv_ogm_reschedule);
|
||||
|
||||
/* begin scheduling originator messages on that interface */
|
||||
batadv_iv_ogm_schedule(hard_iface);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,6 +83,9 @@ struct batadv_hard_iface_bat_iv {
|
|||
/** @ogm_seqno: OGM sequence number - used to identify each OGM */
|
||||
atomic_t ogm_seqno;
|
||||
|
||||
/** @reschedule_work: recover OGM schedule after schedule error */
|
||||
struct delayed_work reschedule_work;
|
||||
|
||||
/** @ogm_buff_mutex: lock protecting ogm_buff and ogm_buff_len */
|
||||
struct mutex ogm_buff_mutex;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user