diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index 87d6b11161e4..0461f11227d0 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@ -513,7 +513,7 @@ batadv_bla_get_backbone_gw(struct batadv_priv *bat_priv, const u8 *orig, return NULL; entry->vid = vid; - entry->lasttime = jiffies; + WRITE_ONCE(entry->lasttime, jiffies); entry->crc = BATADV_BLA_CRC_INIT; entry->bat_priv = bat_priv; spin_lock_init(&entry->crc_lock); @@ -581,7 +581,7 @@ batadv_bla_update_own_backbone_gw(struct batadv_priv *bat_priv, if (unlikely(!backbone_gw)) return; - backbone_gw->lasttime = jiffies; + WRITE_ONCE(backbone_gw->lasttime, jiffies); batadv_backbone_gw_put(backbone_gw); } @@ -715,7 +715,7 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv, ether_addr_copy(claim->addr, mac); spin_lock_init(&claim->backbone_lock); claim->vid = vid; - claim->lasttime = jiffies; + WRITE_ONCE(claim->lasttime, jiffies); kref_get(&backbone_gw->refcount); claim->backbone_gw = backbone_gw; kref_init(&claim->refcount); @@ -737,7 +737,7 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv, return; } } else { - claim->lasttime = jiffies; + WRITE_ONCE(claim->lasttime, jiffies); if (claim->backbone_gw == backbone_gw) /* no need to register a new backbone */ goto claim_free_ref; @@ -770,7 +770,7 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv, spin_lock_bh(&backbone_gw->crc_lock); backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN); spin_unlock_bh(&backbone_gw->crc_lock); - backbone_gw->lasttime = jiffies; + WRITE_ONCE(backbone_gw->lasttime, jiffies); claim_free_ref: batadv_claim_put(claim); @@ -859,7 +859,7 @@ static bool batadv_handle_announce(struct batadv_priv *bat_priv, u8 *an_addr, return true; /* handle as ANNOUNCE frame */ - backbone_gw->lasttime = jiffies; + WRITE_ONCE(backbone_gw->lasttime, jiffies); crc = ntohs(*((__force __be16 *)(&an_addr[4]))); batadv_dbg(BATADV_DBG_BLA, bat_priv, @@ -1254,7 +1254,7 @@ static void batadv_bla_purge_backbone_gw(struct batadv_priv *bat_priv, int now) head, hash_entry) { if (now) goto purge_now; - if (!batadv_has_timed_out(backbone_gw->lasttime, + if (!batadv_has_timed_out(READ_ONCE(backbone_gw->lasttime), BATADV_BLA_BACKBONE_TIMEOUT)) continue; @@ -1335,7 +1335,7 @@ static void batadv_bla_purge_claims(struct batadv_priv *bat_priv, primary_if->net_dev->dev_addr)) goto skip; - if (!batadv_has_timed_out(claim->lasttime, + if (!batadv_has_timed_out(READ_ONCE(claim->lasttime), BATADV_BLA_CLAIM_TIMEOUT)) goto skip; @@ -1495,7 +1495,7 @@ static void batadv_bla_periodic_work(struct work_struct *work) eth_random_addr(bat_priv->bla.loopdetect_addr); bat_priv->bla.loopdetect_addr[0] = 0xba; bat_priv->bla.loopdetect_addr[1] = 0xbe; - bat_priv->bla.loopdetect_lasttime = jiffies; + WRITE_ONCE(bat_priv->bla.loopdetect_lasttime, jiffies); atomic_set(&bat_priv->bla.loopdetect_next, BATADV_BLA_LOOPDETECT_PERIODS); @@ -1516,7 +1516,7 @@ static void batadv_bla_periodic_work(struct work_struct *work) primary_if->net_dev->dev_addr)) continue; - backbone_gw->lasttime = jiffies; + WRITE_ONCE(backbone_gw->lasttime, jiffies); batadv_bla_send_announce(bat_priv, backbone_gw); if (send_loopdetect) @@ -1900,7 +1900,7 @@ batadv_bla_loopdetect_check(struct batadv_priv *bat_priv, struct sk_buff *skb, /* If the packet came too late, don't forward it on the mesh * but don't consider that as loop. It might be a coincidence. */ - if (batadv_has_timed_out(bat_priv->bla.loopdetect_lasttime, + if (batadv_has_timed_out(READ_ONCE(bat_priv->bla.loopdetect_lasttime), BATADV_BLA_LOOPDETECT_TIMEOUT)) return true; @@ -2015,7 +2015,7 @@ bool batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb, if (own_claim) { /* ... allow it in any case */ - claim->lasttime = jiffies; + WRITE_ONCE(claim->lasttime, jiffies); goto allow; } @@ -2117,7 +2117,7 @@ bool batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb, /* if yes, the client has roamed and we have * to unclaim it. */ - if (batadv_has_timed_out(claim->lasttime, 100)) { + if (batadv_has_timed_out(READ_ONCE(claim->lasttime), 100)) { /* only unclaim if the last claim entry is * older than 100 ms to make sure we really * have a roaming client here. @@ -2362,7 +2362,7 @@ batadv_bla_backbone_dump_entry(struct sk_buff *msg, u32 portid, backbone_crc = backbone_gw->crc; spin_unlock_bh(&backbone_gw->crc_lock); - msecs = jiffies_to_msecs(jiffies - backbone_gw->lasttime); + msecs = jiffies_to_msecs(jiffies - READ_ONCE(backbone_gw->lasttime)); if (is_own) if (nla_put_flag(msg, BATADV_ATTR_BLA_OWN)) { diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index bb3c31b5f259..43ebf86e7b36 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -365,6 +365,28 @@ static u32 batadv_wifi_flags_evaluate(struct net_device *net_device) return wifi_flags; } +/** + * batadv_netdev_get_wifi_flags() - retrieve wifi flags for net_device + * @net_dev: the device to check + * + * Return: batadv_hard_iface_wifi_flags flags of the device + */ +u32 batadv_netdev_get_wifi_flags(struct net_device *net_dev) +{ + struct batadv_wifi_net_device_state *device_state; + u32 wifi_flags = 0; + + rcu_read_lock(); + device_state = rhashtable_lookup_fast(&batadv_wifi_net_devices, + &net_dev, + batadv_wifi_net_devices_params); + if (device_state) + wifi_flags = READ_ONCE(device_state->wifi_flags); + rcu_read_unlock(); + + return wifi_flags; +} + /** * batadv_hardif_get_wifi_flags() - retrieve wifi flags for hard_iface * @hard_iface: the device to check @@ -373,21 +395,10 @@ static u32 batadv_wifi_flags_evaluate(struct net_device *net_device) */ u32 batadv_hardif_get_wifi_flags(struct batadv_hard_iface *hard_iface) { - struct batadv_wifi_net_device_state *device_state; - u32 wifi_flags = 0; - if (!hard_iface) return 0; - rcu_read_lock(); - device_state = rhashtable_lookup_fast(&batadv_wifi_net_devices, - &hard_iface->net_dev, - batadv_wifi_net_devices_params); - if (device_state) - wifi_flags = READ_ONCE(device_state->wifi_flags); - rcu_read_unlock(); - - return wifi_flags; + return batadv_netdev_get_wifi_flags(hard_iface->net_dev); } /** diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h index 089e65c8a481..822e7e378c4d 100644 --- a/net/batman-adv/hard-interface.h +++ b/net/batman-adv/hard-interface.h @@ -70,6 +70,7 @@ extern struct notifier_block batadv_hard_if_notifier; struct net_device *__batadv_get_real_netdev(struct net_device *net_device); struct net_device *batadv_get_real_netdev(struct net_device *net_device); +u32 batadv_netdev_get_wifi_flags(struct net_device *net_dev); u32 batadv_hardif_get_wifi_flags(struct batadv_hard_iface *hard_iface); bool batadv_is_wifi_hardif(struct batadv_hard_iface *hard_iface); struct batadv_hard_iface* diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index 60d4f60066c8..3c4572284b53 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -194,7 +194,8 @@ int batadv_mesh_init(struct net_device *mesh_iface) INIT_HLIST_HEAD(&bat_priv->tvlv.container_list); INIT_HLIST_HEAD(&bat_priv->tvlv.handler_list); INIT_HLIST_HEAD(&bat_priv->meshif_vlan_list); - INIT_HLIST_HEAD(&bat_priv->tp_list); + INIT_HLIST_HEAD(&bat_priv->tp_sender_list); + INIT_HLIST_HEAD(&bat_priv->tp_receiver_list); bat_priv->gw.generation = 0; diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index e5463003a3bd..1ba206e40273 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -919,9 +919,15 @@ static int batadv_netlink_set_hardif(struct sk_buff *skb, #ifdef CONFIG_BATMAN_ADV_BATMAN_V if (info->attrs[BATADV_ATTR_ELP_INTERVAL]) { - attr = info->attrs[BATADV_ATTR_ELP_INTERVAL]; + u32 elp_interval; - WRITE_ONCE(hard_iface->bat_v.elp_interval, nla_get_u32(attr)); + attr = info->attrs[BATADV_ATTR_ELP_INTERVAL]; + elp_interval = nla_get_u32(attr); + + elp_interval = min_t(u32, elp_interval, INT_MAX); + elp_interval = max_t(u32, elp_interval, BATADV_JITTER); + + WRITE_ONCE(hard_iface->bat_v.elp_interval, elp_interval); } if (info->attrs[BATADV_ATTR_THROUGHPUT_OVERRIDE]) { diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c index aefe757277b2..978e32d94e6c 100644 --- a/net/batman-adv/tp_meter.c +++ b/net/batman-adv/tp_meter.c @@ -142,30 +142,27 @@ static u32 batadv_tp_cwnd(u32 base, u32 increment, u32 min) * 2) if the session is in Congestion Avoidance, the CWND has to be * increased by MSS * MSS / CWND for every unique received ACK */ -static void batadv_tp_update_cwnd(struct batadv_tp_vars *tp_vars, u32 mss) +static void batadv_tp_update_cwnd(struct batadv_tp_sender *tp_vars, u32 mss) + __must_hold(&tp_vars->cc_lock) { - spin_lock_bh(&tp_vars->cwnd_lock); - /* slow start... */ - if (tp_vars->cwnd <= tp_vars->ss_threshold) { - tp_vars->dec_cwnd = 0; - tp_vars->cwnd = batadv_tp_cwnd(tp_vars->cwnd, mss, mss); - spin_unlock_bh(&tp_vars->cwnd_lock); + if (tp_vars->cc.cwnd <= tp_vars->cc.ss_threshold) { + tp_vars->cc.dec_cwnd = 0; + tp_vars->cc.cwnd = batadv_tp_cwnd(tp_vars->cc.cwnd, mss, mss); return; } + /* prevent overflow in (mss * mss) << 3 */ + mss = min_t(u32, mss, (1U << 14) - 1); + /* increment CWND at least of 1 (section 3.1 of RFC5681) */ - tp_vars->dec_cwnd += max_t(u32, 1U << 3, - ((mss * mss) << 6) / (tp_vars->cwnd << 3)); - if (tp_vars->dec_cwnd < (mss << 3)) { - spin_unlock_bh(&tp_vars->cwnd_lock); + tp_vars->cc.dec_cwnd += max_t(u32, 1U << 3, + ((mss * mss) << 3) / tp_vars->cc.cwnd); + if (tp_vars->cc.dec_cwnd < (mss << 3)) return; - } - tp_vars->cwnd = batadv_tp_cwnd(tp_vars->cwnd, mss, mss); - tp_vars->dec_cwnd = 0; - - spin_unlock_bh(&tp_vars->cwnd_lock); + tp_vars->cc.cwnd = batadv_tp_cwnd(tp_vars->cc.cwnd, mss, mss); + tp_vars->cc.dec_cwnd = 0; } /** @@ -173,8 +170,9 @@ static void batadv_tp_update_cwnd(struct batadv_tp_vars *tp_vars, u32 mss) * @tp_vars: the private data of the current TP meter session * @new_rtt: new roundtrip time in msec */ -static void batadv_tp_update_rto(struct batadv_tp_vars *tp_vars, +static void batadv_tp_update_rto(struct batadv_tp_sender *tp_vars, u32 new_rtt) + __must_hold(&tp_vars->cc_lock) { long m = new_rtt; @@ -184,24 +182,24 @@ static void batadv_tp_update_rto(struct batadv_tp_vars *tp_vars, * It's tricky to understand. Don't lose hair please. * Inspired by tcp_rtt_estimator() tcp_input.c */ - if (tp_vars->srtt != 0) { - m -= (tp_vars->srtt >> 3); /* m is now error in rtt est */ - tp_vars->srtt += m; /* rtt = 7/8 srtt + 1/8 new */ + if (tp_vars->cc.srtt != 0) { + m -= (tp_vars->cc.srtt >> 3); /* m is now error in rtt est */ + tp_vars->cc.srtt += m; /* rtt = 7/8 srtt + 1/8 new */ if (m < 0) m = -m; - m -= (tp_vars->rttvar >> 2); - tp_vars->rttvar += m; /* mdev ~= 3/4 rttvar + 1/4 new */ + m -= (tp_vars->cc.rttvar >> 2); + tp_vars->cc.rttvar += m; /* mdev ~= 3/4 rttvar + 1/4 new */ } else { /* first measure getting in */ - tp_vars->srtt = m << 3; /* take the measured time to be srtt */ - tp_vars->rttvar = m << 1; /* new_rtt / 2 */ + tp_vars->cc.srtt = m << 3; /* take the measured time to be srtt */ + tp_vars->cc.rttvar = m << 1; /* new_rtt / 2 */ } /* rto = srtt + 4 * rttvar. * rttvar is scaled by 4, therefore doesn't need to be multiplied */ - tp_vars->rto = (tp_vars->srtt >> 3) + tp_vars->rttvar; + WRITE_ONCE(tp_vars->cc.rto, (tp_vars->cc.srtt >> 3) + tp_vars->cc.rttvar); } /** @@ -252,35 +250,30 @@ static void batadv_tp_batctl_error_notify(enum batadv_tp_meter_reason reason, } /** - * batadv_tp_list_find() - find a tp_vars object in the global list + * batadv_tp_list_find_sender() - find a sender tp_vars object in the global list * @bat_priv: the bat priv with all the mesh interface information * @dst: the other endpoint MAC address to look for - * @role: role of the session * * Look for a tp_vars object matching dst as end_point and return it after * having increment the refcounter. Return NULL is not found * * Return: matching tp_vars or NULL when no tp_vars with @dst was found */ -static struct batadv_tp_vars *batadv_tp_list_find(struct batadv_priv *bat_priv, - const u8 *dst, - enum batadv_tp_meter_role role) +static struct batadv_tp_sender * +batadv_tp_list_find_sender(struct batadv_priv *bat_priv, const u8 *dst) { - struct batadv_tp_vars *pos, *tp_vars = NULL; + struct batadv_tp_sender *pos, *tp_vars = NULL; rcu_read_lock(); - hlist_for_each_entry_rcu(pos, &bat_priv->tp_list, list) { - if (!batadv_compare_eth(pos->other_end, dst)) - continue; - - if (pos->role != role) + hlist_for_each_entry_rcu(pos, &bat_priv->tp_sender_list, common.list) { + if (!batadv_compare_eth(pos->common.other_end, dst)) continue; /* most of the time this function is invoked during the normal * process..it makes sens to pay more when the session is * finished and to speed the process up during the measurement */ - if (unlikely(!kref_get_unless_zero(&pos->refcount))) + if (unlikely(!kref_get_unless_zero(&pos->common.refcount))) continue; tp_vars = pos; @@ -301,10 +294,16 @@ static struct batadv_tp_vars *batadv_tp_list_find(struct batadv_priv *bat_priv, static bool batadv_tp_list_active(struct batadv_priv *bat_priv, const u8 *dst) __must_hold(&bat_priv->tp_list_lock) { - struct batadv_tp_vars *tp_vars; + struct batadv_tp_receiver *tp_receiver; + struct batadv_tp_sender *tp_sender; - hlist_for_each_entry_rcu(tp_vars, &bat_priv->tp_list, list) { - if (batadv_compare_eth(tp_vars->other_end, dst)) + hlist_for_each_entry_rcu(tp_sender, &bat_priv->tp_sender_list, common.list) { + if (batadv_compare_eth(tp_sender->common.other_end, dst)) + return true; + } + + hlist_for_each_entry_rcu(tp_receiver, &bat_priv->tp_receiver_list, common.list) { + if (batadv_compare_eth(tp_receiver->common.other_end, dst)) return true; } @@ -312,12 +311,11 @@ static bool batadv_tp_list_active(struct batadv_priv *bat_priv, const u8 *dst) } /** - * batadv_tp_list_find_session() - find tp_vars session object in the global - * list + * batadv_tp_list_find_sender_session() - find tp_vars sender session + * object in the global list * @bat_priv: the bat priv with all the mesh interface information * @dst: the other endpoint MAC address to look for * @session: session identifier - * @role: role of the session * * Look for a tp_vars object matching dst as end_point, session as tp meter * session and return it after having increment the refcounter. Return NULL @@ -325,28 +323,25 @@ static bool batadv_tp_list_active(struct batadv_priv *bat_priv, const u8 *dst) * * Return: matching tp_vars or NULL when no tp_vars was found */ -static struct batadv_tp_vars * -batadv_tp_list_find_session(struct batadv_priv *bat_priv, const u8 *dst, - const u8 *session, enum batadv_tp_meter_role role) +static struct batadv_tp_sender * +batadv_tp_list_find_sender_session(struct batadv_priv *bat_priv, const u8 *dst, + const u8 *session) { - struct batadv_tp_vars *pos, *tp_vars = NULL; + struct batadv_tp_sender *pos, *tp_vars = NULL; rcu_read_lock(); - hlist_for_each_entry_rcu(pos, &bat_priv->tp_list, list) { - if (!batadv_compare_eth(pos->other_end, dst)) + hlist_for_each_entry_rcu(pos, &bat_priv->tp_sender_list, common.list) { + if (!batadv_compare_eth(pos->common.other_end, dst)) continue; - if (memcmp(pos->session, session, sizeof(pos->session)) != 0) - continue; - - if (pos->role != role) + if (memcmp(pos->common.session, session, sizeof(pos->common.session)) != 0) continue; /* most of the time this function is invoked during the normal * process..it makes sense to pay more when the session is * finished and to speed the process up during the measurement */ - if (unlikely(!kref_get_unless_zero(&pos->refcount))) + if (unlikely(!kref_get_unless_zero(&pos->common.refcount))) continue; tp_vars = pos; @@ -358,16 +353,16 @@ batadv_tp_list_find_session(struct batadv_priv *bat_priv, const u8 *dst, } /** - * batadv_tp_vars_release() - release batadv_tp_vars from lists and queue for - * free after rcu grace period + * batadv_tp_vars_common_release() - release batadv_tp_vars_common from lists + * and queue for free after rcu grace period * @ref: kref pointer of the batadv_tp_vars */ -static void batadv_tp_vars_release(struct kref *ref) +static void batadv_tp_vars_common_release(struct kref *ref) { - struct batadv_tp_vars *tp_vars; + struct batadv_tp_vars_common *tp_vars; struct batadv_tp_unacked *un, *safe; - tp_vars = container_of(ref, struct batadv_tp_vars, refcount); + tp_vars = container_of(ref, struct batadv_tp_vars_common, refcount); /* lock should not be needed because this object is now out of any * context! @@ -383,23 +378,25 @@ static void batadv_tp_vars_release(struct kref *ref) } /** - * batadv_tp_vars_put() - decrement the batadv_tp_vars refcounter and possibly - * release it + * batadv_tp_sender_put() - decrement the batadv_tp_sender + * refcounter and possibly release it * @tp_vars: the private data of the current TP meter session to be free'd */ -static void batadv_tp_vars_put(struct batadv_tp_vars *tp_vars) +static void batadv_tp_sender_put(struct batadv_tp_sender *tp_vars) { if (!tp_vars) return; - kref_put(&tp_vars->refcount, batadv_tp_vars_release); + kref_put(&tp_vars->common.refcount, batadv_tp_vars_common_release); } /** - * batadv_tp_list_detach() - remove tp session from mesh session list once + * batadv_tp_list_detach() - remove tp receiver session from mesh session list once * @tp_vars: the private data of the current TP meter session + * + * Return: whether tp_vars was detached from list and reference must be freed */ -static void batadv_tp_list_detach(struct batadv_tp_vars *tp_vars) +static bool batadv_tp_list_detach(struct batadv_tp_vars_common *tp_vars) { bool detached = false; @@ -411,27 +408,27 @@ static void batadv_tp_list_detach(struct batadv_tp_vars *tp_vars) spin_unlock_bh(&tp_vars->bat_priv->tp_list_lock); if (!detached) - return; + return false; atomic_dec(&tp_vars->bat_priv->tp_num); - /* drop list reference */ - batadv_tp_vars_put(tp_vars); + return true; } /** * batadv_tp_sender_cleanup() - cleanup sender data and drop and timer * @tp_vars: the private data of the current TP meter session to cleanup */ -static void batadv_tp_sender_cleanup(struct batadv_tp_vars *tp_vars) +static void batadv_tp_sender_cleanup(struct batadv_tp_sender *tp_vars) { cancel_delayed_work_sync(&tp_vars->finish_work); - batadv_tp_list_detach(tp_vars); + if (batadv_tp_list_detach(&tp_vars->common)) + batadv_tp_sender_put(tp_vars); /* kill the timer and remove its reference */ - timer_shutdown_sync(&tp_vars->timer); - batadv_tp_vars_put(tp_vars); + timer_shutdown_sync(&tp_vars->common.timer); + batadv_tp_sender_put(tp_vars); } /** @@ -440,7 +437,7 @@ static void batadv_tp_sender_cleanup(struct batadv_tp_vars *tp_vars) * @tp_vars: the private data of the current TP meter session */ static void batadv_tp_sender_end(struct batadv_priv *bat_priv, - struct batadv_tp_vars *tp_vars) + struct batadv_tp_sender *tp_vars) { enum batadv_tp_meter_reason reason; u32 session_cookie; @@ -449,21 +446,21 @@ static void batadv_tp_sender_end(struct batadv_priv *bat_priv, batadv_dbg(BATADV_DBG_TP_METER, bat_priv, "Test towards %pM finished..shutting down (reason=%d)\n", - tp_vars->other_end, reason); + tp_vars->common.other_end, reason); batadv_dbg(BATADV_DBG_TP_METER, bat_priv, "Last timing stats: SRTT=%ums RTTVAR=%ums RTO=%ums\n", - tp_vars->srtt >> 3, tp_vars->rttvar >> 2, tp_vars->rto); + tp_vars->cc.srtt >> 3, tp_vars->cc.rttvar >> 2, tp_vars->cc.rto); batadv_dbg(BATADV_DBG_TP_METER, bat_priv, "Final values: cwnd=%u ss_threshold=%u\n", - tp_vars->cwnd, tp_vars->ss_threshold); + tp_vars->cc.cwnd, tp_vars->cc.ss_threshold); - session_cookie = batadv_tp_session_cookie(tp_vars->session, + session_cookie = batadv_tp_session_cookie(tp_vars->common.session, tp_vars->icmp_uid); batadv_tp_batctl_notify(reason, - tp_vars->other_end, + tp_vars->common.other_end, bat_priv, tp_vars->start_time, atomic64_read(&tp_vars->tot_sent), @@ -475,7 +472,7 @@ static void batadv_tp_sender_end(struct batadv_priv *bat_priv, * @tp_vars: the private data of the current TP meter session * @reason: reason for tp meter session stop */ -static void batadv_tp_sender_shutdown(struct batadv_tp_vars *tp_vars, +static void batadv_tp_sender_shutdown(struct batadv_tp_sender *tp_vars, enum batadv_tp_meter_reason reason) { atomic_cmpxchg(&tp_vars->send_result, 0, reason); @@ -487,7 +484,7 @@ static void batadv_tp_sender_shutdown(struct batadv_tp_vars *tp_vars, * * Return: whether stop reason was found */ -static bool batadv_tp_sender_stopped(struct batadv_tp_vars *tp_vars) +static bool batadv_tp_sender_stopped(struct batadv_tp_sender *tp_vars) { return atomic_read(&tp_vars->send_result) != 0; } @@ -499,10 +496,10 @@ static bool batadv_tp_sender_stopped(struct batadv_tp_vars *tp_vars) static void batadv_tp_sender_finish(struct work_struct *work) { struct delayed_work *delayed_work; - struct batadv_tp_vars *tp_vars; + struct batadv_tp_sender *tp_vars; delayed_work = to_delayed_work(work); - tp_vars = container_of(delayed_work, struct batadv_tp_vars, + tp_vars = container_of(delayed_work, struct batadv_tp_sender, finish_work); batadv_tp_sender_shutdown(tp_vars, BATADV_TP_REASON_COMPLETE); @@ -514,7 +511,7 @@ static void batadv_tp_sender_finish(struct work_struct *work) * * Reschedule the timer using tp_vars->rto as delay */ -static void batadv_tp_reset_sender_timer(struct batadv_tp_vars *tp_vars) +static void batadv_tp_reset_sender_timer(struct batadv_tp_sender *tp_vars) { /* most of the time this function is invoked while normal packet * reception... @@ -523,7 +520,8 @@ static void batadv_tp_reset_sender_timer(struct batadv_tp_vars *tp_vars) /* timer ref will be dropped in batadv_tp_sender_cleanup */ return; - mod_timer(&tp_vars->timer, jiffies + msecs_to_jiffies(tp_vars->rto)); + mod_timer(&tp_vars->common.timer, + jiffies + msecs_to_jiffies(READ_ONCE(tp_vars->cc.rto))); } /** @@ -536,14 +534,17 @@ static void batadv_tp_reset_sender_timer(struct batadv_tp_vars *tp_vars) */ static void batadv_tp_sender_timeout(struct timer_list *t) { - struct batadv_tp_vars *tp_vars = timer_container_of(tp_vars, t, timer); - struct batadv_priv *bat_priv = tp_vars->bat_priv; + struct batadv_tp_sender *tp_vars = timer_container_of(tp_vars, t, common.timer); + struct batadv_priv *bat_priv = tp_vars->common.bat_priv; if (batadv_tp_sender_stopped(tp_vars)) return; + spin_lock_bh(&tp_vars->cc_lock); + /* if the user waited long enough...shutdown the test */ - if (unlikely(tp_vars->rto >= BATADV_TP_MAX_RTO)) { + if (unlikely(tp_vars->cc.rto >= BATADV_TP_MAX_RTO)) { + spin_unlock_bh(&tp_vars->cc_lock); batadv_tp_sender_shutdown(tp_vars, BATADV_TP_REASON_DST_UNREACHABLE); return; @@ -552,25 +553,24 @@ static void batadv_tp_sender_timeout(struct timer_list *t) /* RTO exponential backoff * Details in Section 5.5 of RFC6298 */ - tp_vars->rto <<= 1; + WRITE_ONCE(tp_vars->cc.rto, tp_vars->cc.rto * 2); - spin_lock_bh(&tp_vars->cwnd_lock); - - tp_vars->ss_threshold = tp_vars->cwnd >> 1; - if (tp_vars->ss_threshold < BATADV_TP_PLEN * 2) - tp_vars->ss_threshold = BATADV_TP_PLEN * 2; + tp_vars->cc.ss_threshold = tp_vars->cc.cwnd >> 1; + if (tp_vars->cc.ss_threshold < BATADV_TP_PLEN * 2) + tp_vars->cc.ss_threshold = BATADV_TP_PLEN * 2; batadv_dbg(BATADV_DBG_TP_METER, bat_priv, "Meter: RTO fired during test towards %pM! cwnd=%u new ss_thr=%u, resetting last_sent to %u\n", - tp_vars->other_end, tp_vars->cwnd, tp_vars->ss_threshold, - atomic_read(&tp_vars->last_acked)); + tp_vars->common.other_end, tp_vars->cc.cwnd, tp_vars->cc.ss_threshold, + tp_vars->cc.last_acked); - tp_vars->cwnd = BATADV_TP_PLEN * 3; + tp_vars->cc.cwnd = BATADV_TP_PLEN * 3; - spin_unlock_bh(&tp_vars->cwnd_lock); + WRITE_ONCE(tp_vars->cc.last_sent, tp_vars->cc.last_acked); + + spin_unlock_bh(&tp_vars->cc_lock); /* resend the non-ACKed packets.. */ - tp_vars->last_sent = atomic_read(&tp_vars->last_acked); wake_up(&tp_vars->more_bytes); batadv_tp_reset_sender_timer(tp_vars); @@ -582,7 +582,7 @@ static void batadv_tp_sender_timeout(struct timer_list *t) * @buf: Buffer to fill with bytes * @nbytes: amount of pseudorandom bytes */ -static void batadv_tp_fill_prerandom(struct batadv_tp_vars *tp_vars, +static void batadv_tp_fill_prerandom(struct batadv_tp_sender *tp_vars, u8 *buf, size_t nbytes) { u32 local_offset; @@ -625,7 +625,7 @@ static void batadv_tp_fill_prerandom(struct batadv_tp_vars *tp_vars, * not reachable, BATADV_TP_REASON_MEMORY_ERROR if the packet couldn't be * allocated */ -static int batadv_tp_send_msg(struct batadv_tp_vars *tp_vars, const u8 *src, +static int batadv_tp_send_msg(struct batadv_tp_sender *tp_vars, const u8 *src, struct batadv_orig_node *orig_node, u32 seqno, size_t len, const u8 *session, int uid, u32 timestamp) @@ -668,6 +668,115 @@ static int batadv_tp_send_msg(struct batadv_tp_vars *tp_vars, const u8 *src, return BATADV_TP_REASON_CANT_SEND; } +/** + * enum batadv_tp_ack_reaction - expected reaction to ack packet + */ +enum batadv_tp_ack_reaction { + /** @BATADV_TP_ACK_REACTION_OLD_ACK: ignore old ack packet */ + BATADV_TP_ACK_REACTION_OLD_ACK, + + /** @BATADV_TP_ACK_REACTION_IGNORE: ignore duplicated ack but reset timer */ + BATADV_TP_ACK_REACTION_IGNORE, + + /** @BATADV_TP_ACK_REACTION_RESEND_WAKEUP: resend data and wakeup "more_bytes" */ + BATADV_TP_ACK_REACTION_RESEND_WAKEUP, + + /** @BATADV_TP_ACK_REACTION_WAKEUP: wakeup "more_bytes" */ + BATADV_TP_ACK_REACTION_WAKEUP, +}; + +/** + * batadv_tp_handle_ack() - Calculate reaction to ACK and update congestion control + * @bat_priv: the bat priv with all the mesh interface information + * @tp_vars: the private data of the current TP meter session + * @recv_ack: received ACK seqno + * @mss: maximum segment size for transmission + * + * Return: expected reaction to this ack + */ +static enum batadv_tp_ack_reaction +batadv_tp_handle_ack(struct batadv_priv *bat_priv, + struct batadv_tp_sender *tp_vars, + u32 recv_ack, size_t mss) + __must_hold(&tp_vars->cc_lock) +{ + enum batadv_tp_ack_reaction reaction; + + if (batadv_seq_before(recv_ack, tp_vars->cc.last_acked)) + return BATADV_TP_ACK_REACTION_OLD_ACK; + + /* check if this ACK is a duplicate */ + if (tp_vars->cc.last_acked == recv_ack) { + /* if this is the third duplicate ACK do Fast Retransmit */ + if (tp_vars->cc.dup_acks > 3) + return BATADV_TP_ACK_REACTION_IGNORE; + + tp_vars->cc.dup_acks++; + if (tp_vars->cc.dup_acks != 3) + return BATADV_TP_ACK_REACTION_IGNORE; + + if (!batadv_seq_before(tp_vars->cc.recover, recv_ack)) + return BATADV_TP_ACK_REACTION_IGNORE; + + /* Fast Recovery */ + tp_vars->cc.fast_recovery = true; + + /* Set recover to the last outstanding seqno when Fast Recovery + * is entered. RFC6582, Section 3.2, step 1 + */ + tp_vars->cc.recover = tp_vars->cc.last_sent; + tp_vars->cc.ss_threshold = tp_vars->cc.cwnd >> 1; + batadv_dbg(BATADV_DBG_TP_METER, bat_priv, + "Meter: Fast Recovery, (cur cwnd=%u) ss_thr=%u last_sent=%u recv_ack=%u\n", + tp_vars->cc.cwnd, tp_vars->cc.ss_threshold, + tp_vars->cc.last_sent, recv_ack); + tp_vars->cc.cwnd = batadv_tp_cwnd(tp_vars->cc.ss_threshold, 3 * mss, + mss); + tp_vars->cc.dec_cwnd = 0; + WRITE_ONCE(tp_vars->cc.last_sent, recv_ack); + + return BATADV_TP_ACK_REACTION_RESEND_WAKEUP; + } + + /* count the acked data */ + atomic64_add(recv_ack - tp_vars->cc.last_acked, &tp_vars->tot_sent); + + /* reset the duplicate ACKs counter */ + tp_vars->cc.dup_acks = 0; + + if (tp_vars->cc.fast_recovery) { + /* partial ACK */ + if (batadv_seq_before(recv_ack, tp_vars->cc.recover)) { + /* this is another hole in the window. React + * immediately as specified by NewReno (see + * Section 3.2 of RFC6582 for details) + */ + reaction = BATADV_TP_ACK_REACTION_RESEND_WAKEUP; + tp_vars->cc.cwnd = batadv_tp_cwnd(tp_vars->cc.cwnd, + mss, mss); + } else { + tp_vars->cc.fast_recovery = false; + /* set cwnd to the value of ss_threshold at the + * moment that Fast Recovery was entered. + * RFC6582, Section 3.2, step 3 + */ + tp_vars->cc.cwnd = batadv_tp_cwnd(tp_vars->cc.ss_threshold, + 0, mss); + reaction = BATADV_TP_ACK_REACTION_WAKEUP; + } + } else { + if (recv_ack - tp_vars->cc.last_acked >= mss) + batadv_tp_update_cwnd(tp_vars, mss); + + reaction = BATADV_TP_ACK_REACTION_WAKEUP; + } + + /* move the Transmit Window */ + WRITE_ONCE(tp_vars->cc.last_acked, recv_ack); + + return reaction; +} + /** * batadv_tp_recv_ack() - ACK receiving function * @bat_priv: the bat priv with all the mesh interface information @@ -681,20 +790,23 @@ static void batadv_tp_recv_ack(struct batadv_priv *bat_priv, struct batadv_hard_iface *primary_if = NULL; struct batadv_orig_node *orig_node = NULL; const struct batadv_icmp_tp_packet *icmp; - struct batadv_tp_vars *tp_vars; - const unsigned char *dev_addr; - size_t packet_len, mss; - u32 rtt, recv_ack, cwnd; + enum batadv_tp_ack_reaction reaction; + struct batadv_tp_sender *tp_vars; + size_t packet_len; + u32 recv_ack; + size_t mss; + u32 rtt; packet_len = BATADV_TP_PLEN; mss = BATADV_TP_PLEN; packet_len += sizeof(struct batadv_unicast_packet); icmp = (struct batadv_icmp_tp_packet *)skb->data; + recv_ack = ntohl(icmp->seqno); /* find the tp_vars */ - tp_vars = batadv_tp_list_find_session(bat_priv, icmp->orig, - icmp->session, BATADV_TP_SENDER); + tp_vars = batadv_tp_list_find_sender_session(bat_priv, icmp->orig, + icmp->session); if (unlikely(!tp_vars)) return; @@ -702,8 +814,7 @@ static void batadv_tp_recv_ack(struct batadv_priv *bat_priv, goto out; /* old ACK? silently drop it.. */ - if (batadv_seq_before(ntohl(icmp->seqno), - (u32)atomic_read(&tp_vars->last_acked))) + if (batadv_seq_before(recv_ack, READ_ONCE(tp_vars->cc.last_acked))) goto out; primary_if = batadv_primary_if_get_selected(bat_priv); @@ -714,97 +825,40 @@ static void batadv_tp_recv_ack(struct batadv_priv *bat_priv, if (unlikely(!orig_node)) goto out; + spin_lock_bh(&tp_vars->cc_lock); /* update RTO with the new sampled RTT, if any */ rtt = jiffies_to_msecs(jiffies) - ntohl(icmp->timestamp); if (icmp->timestamp && rtt) batadv_tp_update_rto(tp_vars, rtt); + reaction = batadv_tp_handle_ack(bat_priv, tp_vars, recv_ack, mss); + spin_unlock_bh(&tp_vars->cc_lock); + + if (reaction == BATADV_TP_ACK_REACTION_OLD_ACK) + goto out; + /* ACK for new data... reset the timer */ batadv_tp_reset_sender_timer(tp_vars); - recv_ack = ntohl(icmp->seqno); - - /* check if this ACK is a duplicate */ - if (atomic_read(&tp_vars->last_acked) == recv_ack) { - atomic_inc(&tp_vars->dup_acks); - if (atomic_read(&tp_vars->dup_acks) != 3) - goto out; - - if (recv_ack >= tp_vars->recover) - goto out; - - /* if this is the third duplicate ACK do Fast Retransmit */ + switch (reaction) { + default: + case BATADV_TP_ACK_REACTION_IGNORE: + goto out; + case BATADV_TP_ACK_REACTION_RESEND_WAKEUP: batadv_tp_send_msg(tp_vars, primary_if->net_dev->dev_addr, orig_node, recv_ack, packet_len, icmp->session, icmp->uid, jiffies_to_msecs(jiffies)); - - spin_lock_bh(&tp_vars->cwnd_lock); - - /* Fast Recovery */ - tp_vars->fast_recovery = true; - /* Set recover to the last outstanding seqno when Fast Recovery - * is entered. RFC6582, Section 3.2, step 1 - */ - tp_vars->recover = tp_vars->last_sent; - tp_vars->ss_threshold = tp_vars->cwnd >> 1; - batadv_dbg(BATADV_DBG_TP_METER, bat_priv, - "Meter: Fast Recovery, (cur cwnd=%u) ss_thr=%u last_sent=%u recv_ack=%u\n", - tp_vars->cwnd, tp_vars->ss_threshold, - tp_vars->last_sent, recv_ack); - tp_vars->cwnd = batadv_tp_cwnd(tp_vars->ss_threshold, 3 * mss, - mss); - tp_vars->dec_cwnd = 0; - tp_vars->last_sent = recv_ack; - - spin_unlock_bh(&tp_vars->cwnd_lock); - } else { - /* count the acked data */ - atomic64_add(recv_ack - atomic_read(&tp_vars->last_acked), - &tp_vars->tot_sent); - /* reset the duplicate ACKs counter */ - atomic_set(&tp_vars->dup_acks, 0); - - if (tp_vars->fast_recovery) { - /* partial ACK */ - if (batadv_seq_before(recv_ack, tp_vars->recover)) { - /* this is another hole in the window. React - * immediately as specified by NewReno (see - * Section 3.2 of RFC6582 for details) - */ - dev_addr = primary_if->net_dev->dev_addr; - batadv_tp_send_msg(tp_vars, dev_addr, - orig_node, recv_ack, - packet_len, icmp->session, - icmp->uid, - jiffies_to_msecs(jiffies)); - tp_vars->cwnd = batadv_tp_cwnd(tp_vars->cwnd, - mss, mss); - } else { - tp_vars->fast_recovery = false; - /* set cwnd to the value of ss_threshold at the - * moment that Fast Recovery was entered. - * RFC6582, Section 3.2, step 3 - */ - cwnd = batadv_tp_cwnd(tp_vars->ss_threshold, 0, - mss); - tp_vars->cwnd = cwnd; - } - goto move_twnd; - } - - if (recv_ack - atomic_read(&tp_vars->last_acked) >= mss) - batadv_tp_update_cwnd(tp_vars, mss); -move_twnd: - /* move the Transmit Window */ - atomic_set(&tp_vars->last_acked, recv_ack); + fallthrough; + case BATADV_TP_ACK_REACTION_WAKEUP: + wake_up(&tp_vars->more_bytes); + break; } - wake_up(&tp_vars->more_bytes); out: batadv_hardif_put(primary_if); batadv_orig_node_put(orig_node); - batadv_tp_vars_put(tp_vars); + batadv_tp_sender_put(tp_vars); } /** @@ -814,13 +868,21 @@ static void batadv_tp_recv_ack(struct batadv_priv *bat_priv, * * Return: true when congestion window is not full, false otherwise */ -static bool batadv_tp_avail(struct batadv_tp_vars *tp_vars, +static bool batadv_tp_avail(struct batadv_tp_sender *tp_vars, size_t payload_len) { u32 win_left, win_limit; - win_limit = atomic_read(&tp_vars->last_acked) + tp_vars->cwnd; - win_left = win_limit - tp_vars->last_sent; + spin_lock_bh(&tp_vars->cc_lock); + + win_limit = tp_vars->cc.last_acked + tp_vars->cc.cwnd; + + if (batadv_seq_before(tp_vars->cc.last_sent, win_limit)) + win_left = win_limit - tp_vars->cc.last_sent; + else + win_left = 0; + + spin_unlock_bh(&tp_vars->cc_lock); return win_left >= payload_len; } @@ -836,7 +898,7 @@ static bool batadv_tp_avail(struct batadv_tp_vars *tp_vars, * remaining jiffies (at least 1) if the condition evaluated to true before * the timeout elapsed, or -ERESTARTSYS if it was interrupted by a signal. */ -static int batadv_tp_wait_available(struct batadv_tp_vars *tp_vars, size_t plen) +static int batadv_tp_wait_available(struct batadv_tp_sender *tp_vars, size_t plen) { int ret; @@ -855,20 +917,15 @@ static int batadv_tp_wait_available(struct batadv_tp_vars *tp_vars, size_t plen) */ static int batadv_tp_send(void *arg) { - struct batadv_tp_vars *tp_vars = arg; - struct batadv_priv *bat_priv = tp_vars->bat_priv; + struct batadv_tp_sender *tp_vars = arg; + struct batadv_priv *bat_priv = tp_vars->common.bat_priv; struct batadv_hard_iface *primary_if = NULL; struct batadv_orig_node *orig_node = NULL; size_t payload_len, packet_len; + u32 last_sent; int err = 0; - if (unlikely(tp_vars->role != BATADV_TP_SENDER)) { - err = BATADV_TP_REASON_DST_UNREACHABLE; - batadv_tp_sender_shutdown(tp_vars, err); - goto out; - } - - orig_node = batadv_orig_hash_find(bat_priv, tp_vars->other_end); + orig_node = batadv_orig_hash_find(bat_priv, tp_vars->common.other_end); if (unlikely(!orig_node)) { err = BATADV_TP_REASON_DST_UNREACHABLE; batadv_tp_sender_shutdown(tp_vars, err); @@ -907,11 +964,11 @@ static int batadv_tp_send(void *arg) * the size of the unicast header */ packet_len = payload_len + sizeof(struct batadv_unicast_packet); + last_sent = READ_ONCE(tp_vars->cc.last_sent); err = batadv_tp_send_msg(tp_vars, primary_if->net_dev->dev_addr, - orig_node, tp_vars->last_sent, - packet_len, - tp_vars->session, tp_vars->icmp_uid, + orig_node, last_sent, packet_len, + tp_vars->common.session, tp_vars->icmp_uid, jiffies_to_msecs(jiffies)); /* something went wrong during the preparation/transmission */ @@ -925,8 +982,12 @@ static int batadv_tp_send(void *arg) } /* right-shift the TWND */ - if (!err) - tp_vars->last_sent += payload_len; + if (!err) { + spin_lock_bh(&tp_vars->cc_lock); + if (tp_vars->cc.last_sent == last_sent) + WRITE_ONCE(tp_vars->cc.last_sent, last_sent + payload_len); + spin_unlock_bh(&tp_vars->cc_lock); + } cond_resched(); } @@ -939,7 +1000,7 @@ static int batadv_tp_send(void *arg) batadv_tp_sender_cleanup(tp_vars); complete(&tp_vars->finished); - batadv_tp_vars_put(tp_vars); + batadv_tp_sender_put(tp_vars); return 0; } @@ -949,24 +1010,24 @@ static int batadv_tp_send(void *arg) * sender * @tp_vars: the private data of the current TP meter session */ -static void batadv_tp_start_kthread(struct batadv_tp_vars *tp_vars) +static void batadv_tp_start_kthread(struct batadv_tp_sender *tp_vars) { struct task_struct *kthread; - struct batadv_priv *bat_priv = tp_vars->bat_priv; + struct batadv_priv *bat_priv = tp_vars->common.bat_priv; u32 session_cookie; - kref_get(&tp_vars->refcount); + kref_get(&tp_vars->common.refcount); kthread = kthread_create(batadv_tp_send, tp_vars, "kbatadv_tp_meter"); if (IS_ERR(kthread)) { - session_cookie = batadv_tp_session_cookie(tp_vars->session, + session_cookie = batadv_tp_session_cookie(tp_vars->common.session, tp_vars->icmp_uid); pr_err("batadv: cannot create tp meter kthread\n"); batadv_tp_batctl_error_notify(BATADV_TP_REASON_MEMORY_ERROR, - tp_vars->other_end, + tp_vars->common.other_end, bat_priv, session_cookie); /* drop reserved reference for kthread */ - batadv_tp_vars_put(tp_vars); + batadv_tp_sender_put(tp_vars); /* cleanup of failed tp meter variables */ batadv_tp_sender_cleanup(tp_vars); @@ -987,7 +1048,7 @@ static void batadv_tp_start_kthread(struct batadv_tp_vars *tp_vars) void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst, u32 test_length, u32 *cookie) { - struct batadv_tp_vars *tp_vars; + struct batadv_tp_sender *tp_vars; u8 session_id[2]; u8 icmp_uid; u32 session_cookie; @@ -1037,76 +1098,78 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst, } /* initialize tp_vars */ - ether_addr_copy(tp_vars->other_end, dst); - kref_init(&tp_vars->refcount); - tp_vars->role = BATADV_TP_SENDER; + ether_addr_copy(tp_vars->common.other_end, dst); + kref_init(&tp_vars->common.refcount); atomic_set(&tp_vars->send_result, 0); - memcpy(tp_vars->session, session_id, sizeof(session_id)); + memcpy(tp_vars->common.session, session_id, sizeof(session_id)); tp_vars->icmp_uid = icmp_uid; - tp_vars->last_sent = BATADV_TP_FIRST_SEQ; - atomic_set(&tp_vars->last_acked, BATADV_TP_FIRST_SEQ); - tp_vars->fast_recovery = false; - tp_vars->recover = BATADV_TP_FIRST_SEQ; + WRITE_ONCE(tp_vars->cc.last_sent, BATADV_TP_FIRST_SEQ); + WRITE_ONCE(tp_vars->cc.dup_acks, 0); + WRITE_ONCE(tp_vars->cc.last_acked, BATADV_TP_FIRST_SEQ); + tp_vars->cc.fast_recovery = false; + tp_vars->cc.recover = BATADV_TP_FIRST_SEQ; /* initialise the CWND to 3*MSS (Section 3.1 in RFC5681). * For batman-adv the MSS is the size of the payload received by the * mesh_interface, hence its MTU */ - tp_vars->cwnd = BATADV_TP_PLEN * 3; + tp_vars->cc.cwnd = BATADV_TP_PLEN * 3; + tp_vars->cc.dec_cwnd = 0; + /* at the beginning initialise the SS threshold to the biggest possible * window size, hence the AWND size */ - tp_vars->ss_threshold = BATADV_TP_AWND; + tp_vars->cc.ss_threshold = BATADV_TP_AWND; /* RTO initial value is 3 seconds. * Details in Section 2.1 of RFC6298 */ - tp_vars->rto = 1000; - tp_vars->srtt = 0; - tp_vars->rttvar = 0; + WRITE_ONCE(tp_vars->cc.rto, 1000); + tp_vars->cc.srtt = 0; + tp_vars->cc.rttvar = 0; atomic64_set(&tp_vars->tot_sent, 0); - kref_get(&tp_vars->refcount); - timer_setup(&tp_vars->timer, batadv_tp_sender_timeout, 0); + kref_get(&tp_vars->common.refcount); + timer_setup(&tp_vars->common.timer, batadv_tp_sender_timeout, 0); - tp_vars->bat_priv = bat_priv; + tp_vars->common.bat_priv = bat_priv; tp_vars->start_time = jiffies; init_waitqueue_head(&tp_vars->more_bytes); init_completion(&tp_vars->finished); - spin_lock_init(&tp_vars->unacked_lock); - INIT_LIST_HEAD(&tp_vars->unacked_list); + spin_lock_init(&tp_vars->common.unacked_lock); + INIT_LIST_HEAD(&tp_vars->common.unacked_list); - spin_lock_init(&tp_vars->cwnd_lock); + spin_lock_init(&tp_vars->cc_lock); tp_vars->prerandom_offset = 0; spin_lock_init(&tp_vars->prerandom_lock); - kref_get(&tp_vars->refcount); - hlist_add_head_rcu(&tp_vars->list, &bat_priv->tp_list); - spin_unlock_bh(&bat_priv->tp_list_lock); - tp_vars->test_length = test_length; if (!tp_vars->test_length) tp_vars->test_length = BATADV_TP_DEF_TEST_LENGTH; + /* init work item for finished tp tests */ + INIT_DELAYED_WORK(&tp_vars->finish_work, batadv_tp_sender_finish); + + kref_get(&tp_vars->common.refcount); + hlist_add_head_rcu(&tp_vars->common.list, &bat_priv->tp_sender_list); + spin_unlock_bh(&bat_priv->tp_list_lock); + batadv_dbg(BATADV_DBG_TP_METER, bat_priv, "Meter: starting throughput meter towards %pM (length=%ums)\n", dst, test_length); - /* init work item for finished tp tests */ - INIT_DELAYED_WORK(&tp_vars->finish_work, batadv_tp_sender_finish); - /* start tp kthread. This way the write() call issued from userspace can * happily return and avoid to block */ batadv_tp_start_kthread(tp_vars); /* don't return reference to new tp_vars */ - batadv_tp_vars_put(tp_vars); + batadv_tp_sender_put(tp_vars); } /** @@ -1119,7 +1182,7 @@ void batadv_tp_stop(struct batadv_priv *bat_priv, const u8 *dst, u8 return_value) { struct batadv_orig_node *orig_node; - struct batadv_tp_vars *tp_vars; + struct batadv_tp_sender *tp_vars; batadv_dbg(BATADV_DBG_TP_METER, bat_priv, "Meter: stopping test towards %pM\n", dst); @@ -1128,7 +1191,7 @@ void batadv_tp_stop(struct batadv_priv *bat_priv, const u8 *dst, if (!orig_node) return; - tp_vars = batadv_tp_list_find(bat_priv, orig_node->orig, BATADV_TP_SENDER); + tp_vars = batadv_tp_list_find_sender(bat_priv, orig_node->orig); if (!tp_vars) { batadv_dbg(BATADV_DBG_TP_METER, bat_priv, "Meter: trying to interrupt an already over connection\n"); @@ -1136,20 +1199,75 @@ void batadv_tp_stop(struct batadv_priv *bat_priv, const u8 *dst, } batadv_tp_sender_shutdown(tp_vars, return_value); - batadv_tp_vars_put(tp_vars); + batadv_tp_sender_put(tp_vars); out_put_orig_node: batadv_orig_node_put(orig_node); } +/** + * batadv_tp_list_find_receiver_session() - find tp_vars receiver session + * object in the global list + * @bat_priv: the bat priv with all the mesh interface information + * @dst: the other endpoint MAC address to look for + * @session: session identifier + * + * Look for a tp_vars object matching dst as end_point, session as tp meter + * session and return it after having increment the refcounter. Return NULL + * is not found + * + * Return: matching tp_vars or NULL when no tp_vars was found + */ +static struct batadv_tp_receiver * +batadv_tp_list_find_receiver_session(struct batadv_priv *bat_priv, const u8 *dst, + const u8 *session) +{ + struct batadv_tp_receiver *pos, *tp_vars = NULL; + + rcu_read_lock(); + hlist_for_each_entry_rcu(pos, &bat_priv->tp_receiver_list, common.list) { + if (!batadv_compare_eth(pos->common.other_end, dst)) + continue; + + if (memcmp(pos->common.session, session, sizeof(pos->common.session)) != 0) + continue; + + /* most of the time this function is invoked during the normal + * process..it makes sense to pay more when the session is + * finished and to speed the process up during the measurement + */ + if (unlikely(!kref_get_unless_zero(&pos->common.refcount))) + continue; + + tp_vars = pos; + break; + } + rcu_read_unlock(); + + return tp_vars; +} + +/** + * batadv_tp_receiver_put() - decrement the batadv_tp_receiver + * refcounter and possibly release it + * @tp_vars: the private data of the current TP meter session to be free'd + */ +static void batadv_tp_receiver_put(struct batadv_tp_receiver *tp_vars) +{ + if (!tp_vars) + return; + + kref_put(&tp_vars->common.refcount, batadv_tp_vars_common_release); +} + /** * batadv_tp_reset_receiver_timer() - reset the receiver shutdown timer * @tp_vars: the private data of the current TP meter session * * start the receiver shutdown timer or reset it if already started */ -static void batadv_tp_reset_receiver_timer(struct batadv_tp_vars *tp_vars) +static void batadv_tp_reset_receiver_timer(struct batadv_tp_receiver *tp_vars) { - mod_timer(&tp_vars->timer, + mod_timer(&tp_vars->common.timer, jiffies + msecs_to_jiffies(BATADV_TP_RECV_TIMEOUT)); } @@ -1160,11 +1278,11 @@ static void batadv_tp_reset_receiver_timer(struct batadv_tp_vars *tp_vars) */ static void batadv_tp_receiver_shutdown(struct timer_list *t) { - struct batadv_tp_vars *tp_vars = timer_container_of(tp_vars, t, timer); + struct batadv_tp_receiver *tp_vars = timer_container_of(tp_vars, t, common.timer); struct batadv_tp_unacked *un, *safe; struct batadv_priv *bat_priv; - bat_priv = tp_vars->bat_priv; + bat_priv = tp_vars->common.bat_priv; /* if there is recent activity rearm the timer */ if (!batadv_has_timed_out(tp_vars->last_recv_time, @@ -1176,22 +1294,23 @@ static void batadv_tp_receiver_shutdown(struct timer_list *t) batadv_dbg(BATADV_DBG_TP_METER, bat_priv, "Shutting down for inactivity (more than %dms) from %pM\n", - BATADV_TP_RECV_TIMEOUT, tp_vars->other_end); + BATADV_TP_RECV_TIMEOUT, tp_vars->common.other_end); - batadv_tp_list_detach(tp_vars); + if (batadv_tp_list_detach(&tp_vars->common)) + batadv_tp_receiver_put(tp_vars); - spin_lock_bh(&tp_vars->unacked_lock); - list_for_each_entry_safe(un, safe, &tp_vars->unacked_list, list) { + spin_lock_bh(&tp_vars->common.unacked_lock); + list_for_each_entry_safe(un, safe, &tp_vars->common.unacked_list, list) { list_del(&un->list); kfree(un); } - spin_unlock_bh(&tp_vars->unacked_lock); + spin_unlock_bh(&tp_vars->common.unacked_lock); /* drop reference of timer */ if (WARN_ON(atomic_xchg(&tp_vars->receiving, 0) != 1)) return; - batadv_tp_vars_put(tp_vars); + batadv_tp_receiver_put(tp_vars); } /** @@ -1275,7 +1394,7 @@ static int batadv_tp_send_ack(struct batadv_priv *bat_priv, const u8 *dst, * * Return: true if the packed has been successfully processed, false otherwise */ -static bool batadv_tp_handle_out_of_order(struct batadv_tp_vars *tp_vars, +static bool batadv_tp_handle_out_of_order(struct batadv_tp_receiver *tp_vars, const struct sk_buff *skb) { const struct batadv_icmp_tp_packet *icmp; @@ -1293,10 +1412,10 @@ static bool batadv_tp_handle_out_of_order(struct batadv_tp_vars *tp_vars, payload_len = skb->len - sizeof(struct batadv_unicast_packet); new->len = payload_len; - spin_lock_bh(&tp_vars->unacked_lock); + spin_lock_bh(&tp_vars->common.unacked_lock); /* if the list is empty immediately attach this new object */ - if (list_empty(&tp_vars->unacked_list)) { - list_add(&new->list, &tp_vars->unacked_list); + if (list_empty(&tp_vars->common.unacked_list)) { + list_add(&new->list, &tp_vars->common.unacked_list); goto out; } @@ -1307,7 +1426,7 @@ static bool batadv_tp_handle_out_of_order(struct batadv_tp_vars *tp_vars, * the last received packet (the one being processed now) has a bigger * seqno than all the others already stored. */ - list_for_each_entry_reverse(un, &tp_vars->unacked_list, list) { + list_for_each_entry_reverse(un, &tp_vars->common.unacked_list, list) { /* check for duplicates */ if (new->seqno == un->seqno) { if (new->len > un->len) @@ -1325,17 +1444,17 @@ static bool batadv_tp_handle_out_of_order(struct batadv_tp_vars *tp_vars, * one is attached _after_ it. In this way the list is kept in * ascending order */ - list_add_tail(&new->list, &un->list); + list_add(&new->list, &un->list); added = true; break; } /* received packet with smallest seqno out of order; add it to front */ if (!added) - list_add(&new->list, &tp_vars->unacked_list); + list_add(&new->list, &tp_vars->common.unacked_list); out: - spin_unlock_bh(&tp_vars->unacked_lock); + spin_unlock_bh(&tp_vars->common.unacked_lock); return true; } @@ -1345,7 +1464,7 @@ static bool batadv_tp_handle_out_of_order(struct batadv_tp_vars *tp_vars, * without gaps * @tp_vars: the private data of the current TP meter session */ -static void batadv_tp_ack_unordered(struct batadv_tp_vars *tp_vars) +static void batadv_tp_ack_unordered(struct batadv_tp_receiver *tp_vars) { struct batadv_tp_unacked *un, *safe; u32 to_ack; @@ -1353,8 +1472,8 @@ static void batadv_tp_ack_unordered(struct batadv_tp_vars *tp_vars) /* go through the unacked packet list and possibly ACK them as * well */ - spin_lock_bh(&tp_vars->unacked_lock); - list_for_each_entry_safe(un, safe, &tp_vars->unacked_list, list) { + spin_lock_bh(&tp_vars->common.unacked_lock); + list_for_each_entry_safe(un, safe, &tp_vars->common.unacked_list, list) { /* the list is ordered, therefore it is possible to stop as soon * there is a gap between the last acked seqno and the seqno of * the packet under inspection @@ -1370,7 +1489,7 @@ static void batadv_tp_ack_unordered(struct batadv_tp_vars *tp_vars) list_del(&un->list); kfree(un); } - spin_unlock_bh(&tp_vars->unacked_lock); + spin_unlock_bh(&tp_vars->common.unacked_lock); } /** @@ -1380,18 +1499,18 @@ static void batadv_tp_ack_unordered(struct batadv_tp_vars *tp_vars) * * Return: corresponding tp_vars or NULL on errors */ -static struct batadv_tp_vars * +static struct batadv_tp_receiver * batadv_tp_init_recv(struct batadv_priv *bat_priv, const struct batadv_icmp_tp_packet *icmp) { - struct batadv_tp_vars *tp_vars = NULL; + struct batadv_tp_receiver *tp_vars = NULL; spin_lock_bh(&bat_priv->tp_list_lock); if (READ_ONCE(bat_priv->mesh_state) != BATADV_MESH_ACTIVE) goto out_unlock; - tp_vars = batadv_tp_list_find_session(bat_priv, icmp->orig, - icmp->session, BATADV_TP_RECEIVER); + tp_vars = batadv_tp_list_find_receiver_session(bat_priv, icmp->orig, + icmp->session); if (tp_vars) goto out_unlock; @@ -1407,22 +1526,21 @@ batadv_tp_init_recv(struct batadv_priv *bat_priv, goto out_unlock; } - ether_addr_copy(tp_vars->other_end, icmp->orig); - tp_vars->role = BATADV_TP_RECEIVER; + ether_addr_copy(tp_vars->common.other_end, icmp->orig); atomic_set(&tp_vars->receiving, 1); - memcpy(tp_vars->session, icmp->session, sizeof(tp_vars->session)); + memcpy(tp_vars->common.session, icmp->session, sizeof(tp_vars->common.session)); tp_vars->last_recv = BATADV_TP_FIRST_SEQ; - tp_vars->bat_priv = bat_priv; - kref_init(&tp_vars->refcount); + tp_vars->common.bat_priv = bat_priv; + kref_init(&tp_vars->common.refcount); - spin_lock_init(&tp_vars->unacked_lock); - INIT_LIST_HEAD(&tp_vars->unacked_list); + spin_lock_init(&tp_vars->common.unacked_lock); + INIT_LIST_HEAD(&tp_vars->common.unacked_list); - kref_get(&tp_vars->refcount); - hlist_add_head_rcu(&tp_vars->list, &bat_priv->tp_list); + kref_get(&tp_vars->common.refcount); + timer_setup(&tp_vars->common.timer, batadv_tp_receiver_shutdown, 0); - kref_get(&tp_vars->refcount); - timer_setup(&tp_vars->timer, batadv_tp_receiver_shutdown, 0); + kref_get(&tp_vars->common.refcount); + hlist_add_head_rcu(&tp_vars->common.list, &bat_priv->tp_receiver_list); batadv_tp_reset_receiver_timer(tp_vars); @@ -1443,7 +1561,7 @@ static void batadv_tp_recv_msg(struct batadv_priv *bat_priv, const struct sk_buff *skb) { const struct batadv_icmp_tp_packet *icmp; - struct batadv_tp_vars *tp_vars; + struct batadv_tp_receiver *tp_vars; size_t packet_size; u32 seqno; @@ -1461,8 +1579,8 @@ static void batadv_tp_recv_msg(struct batadv_priv *bat_priv, goto out; } } else { - tp_vars = batadv_tp_list_find_session(bat_priv, icmp->orig, - icmp->session, BATADV_TP_RECEIVER); + tp_vars = batadv_tp_list_find_receiver_session(bat_priv, icmp->orig, + icmp->session); if (!tp_vars) { batadv_dbg(BATADV_DBG_TP_METER, bat_priv, "Unexpected packet from %pM!\n", @@ -1506,7 +1624,7 @@ static void batadv_tp_recv_msg(struct batadv_priv *bat_priv, batadv_tp_send_ack(bat_priv, icmp->orig, tp_vars->last_recv, icmp->timestamp, icmp->session, icmp->uid); out: - batadv_tp_vars_put(tp_vars); + batadv_tp_receiver_put(tp_vars); } /** @@ -1546,45 +1664,58 @@ void batadv_tp_meter_recv(struct batadv_priv *bat_priv, struct sk_buff *skb) */ void batadv_tp_stop_all(struct batadv_priv *bat_priv) { - struct batadv_tp_vars *tp_vars[BATADV_TP_MAX_NUM]; - struct batadv_tp_vars *tp_var; - size_t count = 0; + struct batadv_tp_receiver *tp_receivers[BATADV_TP_MAX_NUM]; + struct batadv_tp_sender *tp_senders[BATADV_TP_MAX_NUM]; + struct batadv_tp_receiver *tp_receiver; + struct batadv_tp_sender *tp_sender; + size_t receiver_count = 0; + size_t sender_count = 0; size_t i; spin_lock_bh(&bat_priv->tp_list_lock); - hlist_for_each_entry(tp_var, &bat_priv->tp_list, list) { - if (WARN_ON_ONCE(count >= BATADV_TP_MAX_NUM)) + hlist_for_each_entry(tp_receiver, &bat_priv->tp_receiver_list, common.list) { + if (WARN_ON_ONCE(receiver_count >= BATADV_TP_MAX_NUM)) break; - if (!kref_get_unless_zero(&tp_var->refcount)) + if (!kref_get_unless_zero(&tp_receiver->common.refcount)) continue; - tp_vars[count++] = tp_var; + tp_receivers[receiver_count++] = tp_receiver; + } + + hlist_for_each_entry(tp_sender, &bat_priv->tp_sender_list, common.list) { + if (WARN_ON_ONCE(sender_count >= BATADV_TP_MAX_NUM)) + break; + + if (!kref_get_unless_zero(&tp_sender->common.refcount)) + continue; + + tp_senders[sender_count++] = tp_sender; } spin_unlock_bh(&bat_priv->tp_list_lock); - for (i = 0; i < count; i++) { - tp_var = tp_vars[i]; + for (i = 0; i < receiver_count; i++) { + tp_receiver = tp_receivers[i]; - switch (tp_var->role) { - case BATADV_TP_SENDER: - batadv_tp_sender_shutdown(tp_var, - BATADV_TP_REASON_CANCEL); - wake_up(&tp_var->more_bytes); - wait_for_completion(&tp_var->finished); - break; - case BATADV_TP_RECEIVER: - batadv_tp_list_detach(tp_var); - timer_shutdown_sync(&tp_var->timer); + if (batadv_tp_list_detach(&tp_receiver->common)) + batadv_tp_receiver_put(tp_receiver); - if (atomic_xchg(&tp_var->receiving, 0) != 1) - break; + timer_shutdown_sync(&tp_receiver->common.timer); - batadv_tp_vars_put(tp_var); - break; - } + if (atomic_xchg(&tp_receiver->receiving, 0) != 0) + batadv_tp_receiver_put(tp_receiver); - batadv_tp_vars_put(tp_var); + batadv_tp_receiver_put(tp_receiver); + } + + for (i = 0; i < sender_count; i++) { + tp_sender = tp_senders[i]; + + batadv_tp_sender_shutdown(tp_sender, BATADV_TP_REASON_CANCEL); + wake_up(&tp_sender->more_bytes); + wait_for_completion(&tp_sender->finished); + + batadv_tp_sender_put(tp_sender); } synchronize_net(); diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 5e134d08a80f..c346e43d47b9 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -596,20 +596,23 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr, struct net *net = dev_net(mesh_iface); struct batadv_meshif_vlan *vlan; struct net_device *in_dev = NULL; - struct batadv_hard_iface *in_hardif = NULL; struct hlist_head *head; struct batadv_tt_orig_list_entry *orig_entry; int hash_added, table_size, packet_size_max; bool ret = false; bool roamed_back = false; + bool iif_is_wifi = false; u8 remote_flags; u32 match_mark; if (ifindex != BATADV_NULL_IFINDEX) in_dev = dev_get_by_index(net, ifindex); - if (in_dev) - in_hardif = batadv_hardif_get_by_netdev(in_dev); + if (in_dev) { + u32 wifi_flags = batadv_netdev_get_wifi_flags(in_dev); + + iif_is_wifi = batadv_is_wifi(wifi_flags); + } tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid); @@ -684,7 +687,7 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr, */ tt_local->common.flags = BATADV_TT_CLIENT_NEW; tt_local->common.vid = vid; - if (batadv_is_wifi_hardif(in_hardif)) + if (iif_is_wifi) tt_local->common.flags |= BATADV_TT_CLIENT_WIFI; kref_init(&tt_local->common.refcount); tt_local->last_seen = jiffies; @@ -743,7 +746,7 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr, */ remote_flags = tt_local->common.flags & BATADV_TT_REMOTE_MASK; - if (batadv_is_wifi_hardif(in_hardif)) + if (iif_is_wifi) tt_local->common.flags |= BATADV_TT_CLIENT_WIFI; else tt_local->common.flags &= ~BATADV_TT_CLIENT_WIFI; @@ -767,7 +770,6 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr, ret = true; out: - batadv_hardif_put(in_hardif); dev_put(in_dev); batadv_tt_local_entry_put(tt_local); batadv_tt_global_entry_put(tt_global); @@ -797,21 +799,22 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node, struct batadv_tvlv_tt_change **tt_change, s32 *tt_len) { - u16 num_vlan = 0; - u16 tvlv_len = 0; struct batadv_tvlv_tt_vlan_data *tt_vlan; struct batadv_orig_node_vlan *vlan; u16 total_entries = 0; size_t change_offset; u8 *tt_change_ptr; + u16 num_vlan = 0; int vlan_entries; u16 sum_entries; + u16 tvlv_len; spin_lock_bh(&orig_node->vlan_list_lock); hlist_for_each_entry(vlan, &orig_node->vlan_list, list) { vlan_entries = atomic_read(&vlan->tt.num_entries); if (check_add_overflow(vlan_entries, total_entries, &sum_entries)) { + tvlv_len = 0; *tt_len = 0; goto out; } @@ -827,12 +830,14 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node, *tt_len = batadv_tt_len(total_entries); if (check_add_overflow(*tt_len, change_offset, &tvlv_len)) { + tvlv_len = 0; *tt_len = 0; goto out; } *tt_data = kmalloc(tvlv_len, GFP_ATOMIC); if (!*tt_data) { + tvlv_len = 0; *tt_len = 0; goto out; } @@ -867,6 +872,7 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node, out: spin_unlock_bh(&orig_node->vlan_list_lock); + return tvlv_len; } @@ -896,13 +902,13 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv, { struct batadv_tvlv_tt_vlan_data *tt_vlan; struct batadv_meshif_vlan *vlan; - size_t change_offset; - u16 num_vlan = 0; u16 total_entries = 0; - u16 tvlv_len; + size_t change_offset; u8 *tt_change_ptr; + u16 num_vlan = 0; int vlan_entries; u16 sum_entries; + u16 tvlv_len; spin_lock_bh(&bat_priv->meshif_vlan_list_lock); hlist_for_each_entry(vlan, &bat_priv->meshif_vlan_list, list) { @@ -910,6 +916,7 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv, if (check_add_overflow(vlan_entries, total_entries, &sum_entries)) { tvlv_len = 0; + *tt_len = 0; goto out; } @@ -925,12 +932,14 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv, if (check_add_overflow(*tt_len, change_offset, &tvlv_len)) { tvlv_len = 0; + *tt_len = 0; goto out; } *tt_data = kmalloc(tvlv_len, GFP_ATOMIC); if (!*tt_data) { tvlv_len = 0; + *tt_len = 0; goto out; } @@ -964,6 +973,7 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv, out: spin_unlock_bh(&bat_priv->meshif_vlan_list_lock); + return tvlv_len; } diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 19c7316889b6..5eb0371def83 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -1336,21 +1336,10 @@ struct batadv_tp_unacked { }; /** - * enum batadv_tp_meter_role - Modus in tp meter session + * struct batadv_tp_vars_common - common tp meter private variables per session */ -enum batadv_tp_meter_role { - /** @BATADV_TP_RECEIVER: Initialized as receiver */ - BATADV_TP_RECEIVER, - - /** @BATADV_TP_SENDER: Initialized as sender */ - BATADV_TP_SENDER -}; - -/** - * struct batadv_tp_vars - tp meter private variables per session - */ -struct batadv_tp_vars { - /** @list: list node for &bat_priv.tp_list */ +struct batadv_tp_vars_common { + /** @list: list node for &bat_priv.tp_sender_list/&bat_priv.tp_receiver_list */ struct hlist_node list; /** @timer: timer for ack (receiver) and retry (sender) */ @@ -1359,40 +1348,32 @@ struct batadv_tp_vars { /** @bat_priv: pointer to the mesh object */ struct batadv_priv *bat_priv; - /** @start_time: start time in jiffies */ - unsigned long start_time; - /** @other_end: mac address of remote */ u8 other_end[ETH_ALEN]; - /** @role: receiver/sender modi */ - enum batadv_tp_meter_role role; - - /** - * @send_result: 0 when sending is ongoing and otherwise - * enum batadv_tp_meter_reason - */ - atomic_t send_result; - - /** @receiving: receiving binary semaphore: 1 if receiving, 0 is not */ - atomic_t receiving; - - /** @finish_work: work item for the finishing procedure */ - struct delayed_work finish_work; - - /** @finished: completion signaled when a sender thread exits */ - struct completion finished; - - /** @test_length: test length in milliseconds */ - u32 test_length; - /** @session: TP session identifier */ u8 session[2]; - /** @icmp_uid: local ICMP "socket" index */ - u8 icmp_uid; + /** @unacked_list: list of unacked packets (meta-info only) */ + struct list_head unacked_list; - /* sender variables */ + /** @unacked_lock: protect unacked_list */ + spinlock_t unacked_lock; + + /** @refcount: number of context where the object is used */ + struct kref refcount; + + /** @rcu: struct used for freeing in an RCU-safe manner */ + struct rcu_head rcu; +}; + +/** struct batadv_tp_sender_cc - congestion control variables */ +struct batadv_tp_sender_cc { + /** @fast_recovery: true if in Fast Recovery mode */ + bool fast_recovery:1; + + /** @dup_acks: duplicate ACKs counter */ + u8 dup_acks; /** @dec_cwnd: decimal part of the cwnd used during linear growth */ u16 dec_cwnd; @@ -1400,9 +1381,6 @@ struct batadv_tp_vars { /** @cwnd: current size of the congestion window */ u32 cwnd; - /** @cwnd_lock: lock do protect @cwnd & @dec_cwnd */ - spinlock_t cwnd_lock; - /** * @ss_threshold: Slow Start threshold. Once cwnd exceeds this value the * connection switches to the Congestion Avoidance state @@ -1410,20 +1388,11 @@ struct batadv_tp_vars { u32 ss_threshold; /** @last_acked: last acked byte */ - atomic_t last_acked; + u32 last_acked; /** @last_sent: last sent byte, not yet acked */ u32 last_sent; - /** @tot_sent: amount of data sent/ACKed so far */ - atomic64_t tot_sent; - - /** @dup_acks: duplicate ACKs counter */ - atomic_t dup_acks; - - /** @fast_recovery: true if in Fast Recovery mode */ - unsigned char fast_recovery:1; - /** @recover: last sent seqno when entering Fast Recovery */ u32 recover; @@ -1435,6 +1404,44 @@ struct batadv_tp_vars { /** @rttvar: RTT variation scaled by 2^2 */ u32 rttvar; +}; + +/** + * struct batadv_tp_sender - sender tp meter private variables per session + */ +struct batadv_tp_sender { + /** @common: common batadv_tp_vars (best be first member) */ + struct batadv_tp_vars_common common; + + /** @start_time: start time in jiffies */ + unsigned long start_time; + + /** + * @send_result: 0 when sending is ongoing and otherwise + * enum batadv_tp_meter_reason + */ + atomic_t send_result; + + /** @finish_work: work item for the finishing procedure */ + struct delayed_work finish_work; + + /** @finished: completion signaled when a sender thread exits */ + struct completion finished; + + /** @test_length: test length in milliseconds */ + u32 test_length; + + /** @icmp_uid: local ICMP "socket" index */ + u8 icmp_uid; + + /** @cc: congestion control variables */ + struct batadv_tp_sender_cc cc; + + /** @cc_lock: lock do protect @cc */ + spinlock_t cc_lock; + + /** @tot_sent: amount of data sent/ACKed so far */ + atomic64_t tot_sent; /** * @more_bytes: waiting queue anchor when waiting for more ack/retry @@ -1447,26 +1454,23 @@ struct batadv_tp_vars { /** @prerandom_lock: spinlock protecting access to prerandom_offset */ spinlock_t prerandom_lock; +}; - /* receiver variables */ +/** + * struct batadv_tp_receiver - receiver tp meter private variables per session + */ +struct batadv_tp_receiver { + /** @common: common batadv_tp_vars (best be first member) */ + struct batadv_tp_vars_common common; + + /** @receiving: receiving binary semaphore: 1 if receiving, 0 is not */ + atomic_t receiving; /** @last_recv: last in-order received packet */ u32 last_recv; - /** @unacked_list: list of unacked packets (meta-info only) */ - struct list_head unacked_list; - - /** @unacked_lock: protect unacked_list */ - spinlock_t unacked_lock; - /** @last_recv_time: time (jiffies) a msg was received */ unsigned long last_recv_time; - - /** @refcount: number of context where the object is used */ - struct kref refcount; - - /** @rcu: struct used for freeing in an RCU-safe manner */ - struct rcu_head rcu; }; /** @@ -1643,8 +1647,11 @@ struct batadv_priv { */ struct hlist_head forw_bcast_list; - /** @tp_list: list of tp sessions */ - struct hlist_head tp_list; + /** @tp_sender_list: list of tp sender sessions */ + struct hlist_head tp_sender_list; + + /** @tp_receiver_list: list of tp receiver sessions */ + struct hlist_head tp_receiver_list; /** @orig_hash: hash table containing mesh participants (orig nodes) */ struct batadv_hashtable *orig_hash;