| 1 | |
| 2 | |
| 3 | *
|
| 4 | * Edo Monticelli, Antonio Quartulli
|
| 5 |
|
| 6 |
|
| 7 | #include "tp_meter.h"
|
| 8 | #include "main.h"
|
| 9 |
|
| 10 | #include <linux/atomic.h>
|
| 11 | #include <linux/bug.h>
|
| 12 | #include <linux/build_bug.h>
|
| 13 | #include <linux/byteorder/generic.h>
|
| 14 | #include <linux/cache.h>
|
| 15 | #include <linux/compiler.h>
|
| 16 | #include <linux/completion.h>
|
| 17 | #include <linux/container_of.h>
|
| 18 | #include <linux/err.h>
|
| 19 | #include <linux/etherdevice.h>
|
| 20 | #include <linux/gfp.h>
|
| 21 | #include <linux/if_ether.h>
|
| 22 | #include <linux/init.h>
|
| 23 | #include <linux/jiffies.h>
|
| 24 | #include <linux/kref.h>
|
| 25 | #include <linux/kthread.h>
|
| 26 | #include <linux/limits.h>
|
| 27 | #include <linux/list.h>
|
| 28 | #include <linux/minmax.h>
|
| 29 | #include <linux/netdevice.h>
|
| 30 | #include <linux/param.h>
|
| 31 | #include <linux/printk.h>
|
| 32 | #include <linux/random.h>
|
| 33 | #include <linux/rculist.h>
|
| 34 | #include <linux/rcupdate.h>
|
| 35 | #include <linux/sched.h>
|
| 36 | #include <linux/skbuff.h>
|
| 37 | #include <linux/slab.h>
|
| 38 | #include <linux/spinlock.h>
|
| 39 | #include <linux/stddef.h>
|
| 40 | #include <linux/string.h>
|
| 41 | #include <linux/timer.h>
|
| 42 | #include <linux/wait.h>
|
| 43 | #include <linux/workqueue.h>
|
| 44 | #include <uapi/linux/batadv_packet.h>
|
| 45 | #include <uapi/linux/batman_adv.h>
|
| 46 |
|
| 47 | #include "hard-interface.h"
|
| 48 | #include "log.h"
|
| 49 | #include "netlink.h"
|
| 50 | #include "originator.h"
|
| 51 | #include "send.h"
|
| 52 |
|
| 53 | |
| 54 | * BATADV_TP_DEF_TEST_LENGTH - Default test length if not specified by the user
|
| 55 | * in milliseconds
|
| 56 |
|
| 57 | #define BATADV_TP_DEF_TEST_LENGTH 10000
|
| 58 |
|
| 59 | |
| 60 | * BATADV_TP_AWND - Advertised window by the receiver (in bytes)
|
| 61 |
|
| 62 | #define BATADV_TP_AWND 0x20000000
|
| 63 |
|
| 64 | |
| 65 | * BATADV_TP_RECV_TIMEOUT - Receiver activity timeout. If the receiver does not
|
| 66 | * get anything for such amount of milliseconds, the connection is killed
|
| 67 |
|
| 68 | #define BATADV_TP_RECV_TIMEOUT 1000
|
| 69 |
|
| 70 | |
| 71 | * BATADV_TP_MAX_RTO - Maximum sender timeout. If the sender RTO gets beyond
|
| 72 | * such amount of milliseconds, the receiver is considered unreachable and the
|
| 73 | * connection is killed
|
| 74 |
|
| 75 | #define BATADV_TP_MAX_RTO 30000
|
| 76 |
|
| 77 | |
| 78 | * BATADV_TP_FIRST_SEQ - First seqno of each session. The number is rather high
|
| 79 | * in order to immediately trigger a wrap around (test purposes)
|
| 80 |
|
| 81 | #define BATADV_TP_FIRST_SEQ ((u32)-1 - 2000)
|
| 82 |
|
| 83 | |
| 84 | * BATADV_TP_PLEN - length of the payload (data after the batadv_unicast header)
|
| 85 | * to simulate
|
| 86 |
|
| 87 | #define BATADV_TP_PLEN (BATADV_TP_PACKET_LEN - ETH_HLEN - \
|
| 88 | sizeof(struct batadv_unicast_packet))
|
| 89 |
|
| 90 | |
| 91 | * BATADV_TP_MAX_UNACKED - maximum number of packets a receiver didn't yet ack
|
| 92 |
|
| 93 | #define BATADV_TP_MAX_UNACKED 100
|
| 94 |
|
| 95 | static u8 batadv_tp_prerandom[4096] __read_mostly;
|
| 96 |
|
| 97 | |
| 98 | * batadv_tp_session_cookie() - generate session cookie based on session ids
|
| 99 | * @session: TP session identifier
|
| 100 | * @icmp_uid: icmp pseudo uid of the tp session
|
| 101 | *
|
| 102 | * Return: 32 bit tp_meter session cookie
|
| 103 |
|
| 104 | static u32 batadv_tp_session_cookie(const u8 session[2], u8 icmp_uid)
|
| 105 | {
|
| 106 | u32 cookie;
|
| 107 |
|
| 108 | cookie = icmp_uid << 16;
|
| 109 | cookie |= session[0] << 8;
|
| 110 | cookie |= session[1];
|
| 111 |
|
| 112 | return cookie;
|
| 113 | }
|
| 114 |
|
| 115 | |
| 116 | * batadv_tp_cwnd() - compute the new cwnd size
|
| 117 | * @base: base cwnd size value
|
| 118 | * @increment: the value to add to base to get the new size
|
| 119 | * @min: minimum cwnd value (usually MSS)
|
| 120 | *
|
| 121 | * Return the new cwnd size and ensure it does not exceed the Advertised
|
| 122 | * Receiver Window size. It is wrapped around safely.
|
| 123 | * For details refer to Section 3.1 of RFC5681
|
| 124 | *
|
| 125 | * Return: new congestion window size in bytes
|
| 126 |
|
| 127 | static u32 batadv_tp_cwnd(u32 base, u32 increment, u32 min)
|
| 128 | {
|
| 129 | u32 new_size = base + increment;
|
| 130 |
|
| 131 |
|
| 132 | if (new_size < base)
|
| 133 | new_size = (u32)ULONG_MAX;
|
| 134 |
|
| 135 | new_size = min_t(u32, new_size, BATADV_TP_AWND);
|
| 136 |
|
| 137 | return max_t(u32, new_size, min);
|
| 138 | }
|
| 139 |
|
| 140 | |
| 141 | * batadv_tp_update_cwnd() - update the Congestion Windows
|
| 142 | * @tp_vars: the private data of the current TP meter session
|
| 143 | * @mss: maximum segment size of transmission
|
| 144 | *
|
| 145 | * 1) if the session is in Slow Start, the CWND has to be increased by 1
|
| 146 | * MSS every unique received ACK
|
| 147 | * 2) if the session is in Congestion Avoidance, the CWND has to be
|
| 148 | * increased by MSS * MSS / CWND for every unique received ACK
|
| 149 |
|
| 150 | static void batadv_tp_update_cwnd(struct batadv_tp_sender *tp_vars, u32 mss)
|
| 151 | __must_hold(&tp_vars->cc_lock)
|
| 152 | {
|
| 153 |
|
| 154 | if (tp_vars->cc.cwnd <= tp_vars->cc.ss_threshold) {
|
| 155 | tp_vars->cc.dec_cwnd = 0;
|
| 156 | tp_vars->cc.cwnd = batadv_tp_cwnd(tp_vars->cc.cwnd, mss, mss);
|
| 157 | return;
|
| 158 | }
|
| 159 |
|
| 160 |
|
| 161 | mss = min_t(u32, mss, (1U << 14) - 1);
|
| 162 |
|
| 163 |
|
| 164 | tp_vars->cc.dec_cwnd += max_t(u32, 1U << 3,
|
| 165 | ((mss * mss) << 3) / tp_vars->cc.cwnd);
|
| 166 | if (tp_vars->cc.dec_cwnd < (mss << 3))
|
| 167 | return;
|
| 168 |
|
| 169 | tp_vars->cc.cwnd = batadv_tp_cwnd(tp_vars->cc.cwnd, mss, mss);
|
| 170 | tp_vars->cc.dec_cwnd = 0;
|
| 171 | }
|
| 172 |
|
| 173 | |
| 174 | * batadv_tp_update_rto() - calculate new retransmission timeout
|
| 175 | * @tp_vars: the private data of the current TP meter session
|
| 176 | * @new_rtt: new roundtrip time in msec
|
| 177 |
|
| 178 | static void batadv_tp_update_rto(struct batadv_tp_sender *tp_vars,
|
| 179 | u32 new_rtt)
|
| 180 | __must_hold(&tp_vars->cc_lock)
|
| 181 | {
|
| 182 | long m = new_rtt;
|
| 183 |
|
| 184 | |
| 185 | * Details in Section 2.2 and 2.3 of RFC6298
|
| 186 | *
|
| 187 | * It's tricky to understand. Don't lose hair please.
|
| 188 | * Inspired by tcp_rtt_estimator() tcp_input.c
|
| 189 |
|
| 190 | if (tp_vars->cc.srtt != 0) {
|
| 191 | m -= (tp_vars->cc.srtt >> 3);
|
| 192 | tp_vars->cc.srtt += m;
|
| 193 | if (m < 0)
|
| 194 | m = -m;
|
| 195 |
|
| 196 | m -= (tp_vars->cc.rttvar >> 2);
|
| 197 | tp_vars->cc.rttvar += m;
|
| 198 | } else {
|
| 199 |
|
| 200 | tp_vars->cc.srtt = m << 3;
|
| 201 | tp_vars->cc.rttvar = m << 1;
|
| 202 | }
|
| 203 |
|
| 204 | |
| 205 | * rttvar is scaled by 4, therefore doesn't need to be multiplied
|
| 206 |
|
| 207 | WRITE_ONCE(tp_vars->cc.rto, (tp_vars->cc.srtt >> 3) + tp_vars->cc.rttvar);
|
| 208 | }
|
| 209 |
|
| 210 | |
| 211 | * batadv_tp_batctl_notify() - send client status result to client
|
| 212 | * @reason: reason for tp meter session stop
|
| 213 | * @dst: destination of tp_meter session
|
| 214 | * @bat_priv: the bat priv with all the mesh interface information
|
| 215 | * @start_time: start of transmission in jiffies
|
| 216 | * @total_sent: bytes acked to the receiver
|
| 217 | * @cookie: cookie of tp_meter session
|
| 218 |
|
| 219 | static void batadv_tp_batctl_notify(enum batadv_tp_meter_reason reason,
|
| 220 | const u8 *dst, struct batadv_priv *bat_priv,
|
| 221 | unsigned long start_time, u64 total_sent,
|
| 222 | u32 cookie)
|
| 223 | {
|
| 224 | u32 total_bytes;
|
| 225 | u32 test_time;
|
| 226 | u8 result;
|
| 227 |
|
| 228 | if (!batadv_tp_is_error(reason)) {
|
| 229 | result = BATADV_TP_REASON_COMPLETE;
|
| 230 | test_time = jiffies_to_msecs(jiffies - start_time);
|
| 231 | total_bytes = total_sent;
|
| 232 | } else {
|
| 233 | result = reason;
|
| 234 | test_time = 0;
|
| 235 | total_bytes = 0;
|
| 236 | }
|
| 237 |
|
| 238 | batadv_netlink_tpmeter_notify(bat_priv, dst, result, test_time,
|
| 239 | total_bytes, cookie);
|
| 240 | }
|
| 241 |
|
| 242 | |
| 243 | * batadv_tp_batctl_error_notify() - send client error result to client
|
| 244 | * @reason: reason for tp meter session stop
|
| 245 | * @dst: destination of tp_meter session
|
| 246 | * @bat_priv: the bat priv with all the mesh interface information
|
| 247 | * @cookie: cookie of tp_meter session
|
| 248 |
|
| 249 | static void batadv_tp_batctl_error_notify(enum batadv_tp_meter_reason reason,
|
| 250 | const u8 *dst,
|
| 251 | struct batadv_priv *bat_priv,
|
| 252 | u32 cookie)
|
| 253 | {
|
| 254 | batadv_tp_batctl_notify(reason, dst, bat_priv, 0, 0, cookie);
|
| 255 | }
|
| 256 |
|
| 257 | |
| 258 | * batadv_tp_list_find_sender() - find a sender tp_vars object in the global list
|
| 259 | * @bat_priv: the bat priv with all the mesh interface information
|
| 260 | * @dst: the other endpoint MAC address to look for
|
| 261 | *
|
| 262 | * Look for a tp_vars object matching dst as end_point and return it after
|
| 263 | * having increment the refcounter. Return NULL is not found
|
| 264 | *
|
| 265 | * Return: matching tp_vars or NULL when no tp_vars with @dst was found
|
| 266 |
|
| 267 | static struct batadv_tp_sender *
|
| 268 | batadv_tp_list_find_sender(struct batadv_priv *bat_priv, const u8 *dst)
|
| 269 | {
|
| 270 | struct batadv_tp_sender *tp_vars = NULL;
|
| 271 | struct batadv_tp_sender *pos;
|
| 272 |
|
| 273 | rcu_read_lock();
|
| 274 | hlist_for_each_entry_rcu(pos, &bat_priv->tp_sender_list, common.list) {
|
| 275 | if (!batadv_compare_eth(pos->common.other_end, dst))
|
| 276 | continue;
|
| 277 |
|
| 278 | |
| 279 | * process..it makes sens to pay more when the session is
|
| 280 | * finished and to speed the process up during the measurement
|
| 281 |
|
| 282 | if (unlikely(!kref_get_unless_zero(&pos->common.refcount)))
|
| 283 | continue;
|
| 284 |
|
| 285 | tp_vars = pos;
|
| 286 | break;
|
| 287 | }
|
| 288 | rcu_read_unlock();
|
| 289 |
|
| 290 | return tp_vars;
|
| 291 | }
|
| 292 |
|
| 293 | |
| 294 | * batadv_tp_list_active() - check if session from/to destination is ongoing
|
| 295 | * @bat_priv: the bat priv with all the mesh interface information
|
| 296 | * @dst: the other endpoint MAC address to look for
|
| 297 | *
|
| 298 | * Return: true if a matching session with @dst was found, false otherwise
|
| 299 |
|
| 300 | static bool batadv_tp_list_active(struct batadv_priv *bat_priv, const u8 *dst)
|
| 301 | __must_hold(&bat_priv->tp_list_lock)
|
| 302 | {
|
| 303 | struct batadv_tp_receiver *tp_receiver;
|
| 304 | struct batadv_tp_sender *tp_sender;
|
| 305 |
|
| 306 | hlist_for_each_entry_rcu(tp_sender, &bat_priv->tp_sender_list, common.list) {
|
| 307 | if (batadv_compare_eth(tp_sender->common.other_end, dst))
|
| 308 | return true;
|
| 309 | }
|
| 310 |
|
| 311 | hlist_for_each_entry_rcu(tp_receiver, &bat_priv->tp_receiver_list, common.list) {
|
| 312 | if (batadv_compare_eth(tp_receiver->common.other_end, dst))
|
| 313 | return true;
|
| 314 | }
|
| 315 |
|
| 316 | return false;
|
| 317 | }
|
| 318 |
|
| 319 | |
| 320 | * batadv_tp_list_find_sender_session() - find tp_vars sender session
|
| 321 | * object in the global list
|
| 322 | * @bat_priv: the bat priv with all the mesh interface information
|
| 323 | * @dst: the other endpoint MAC address to look for
|
| 324 | * @session: session identifier
|
| 325 | *
|
| 326 | * Look for a tp_vars object matching dst as end_point, session as tp meter
|
| 327 | * session and return it after having increment the refcounter. Return NULL
|
| 328 | * is not found
|
| 329 | *
|
| 330 | * Return: matching tp_vars or NULL when no tp_vars was found
|
| 331 |
|
| 332 | static struct batadv_tp_sender *
|
| 333 | batadv_tp_list_find_sender_session(struct batadv_priv *bat_priv, const u8 *dst,
|
| 334 | const u8 *session)
|
| 335 | {
|
| 336 | struct batadv_tp_sender *tp_vars = NULL;
|
| 337 | struct batadv_tp_sender *pos;
|
| 338 |
|
| 339 | rcu_read_lock();
|
| 340 | hlist_for_each_entry_rcu(pos, &bat_priv->tp_sender_list, common.list) {
|
| 341 | if (!batadv_compare_eth(pos->common.other_end, dst))
|
| 342 | continue;
|
| 343 |
|
| 344 | if (memcmp(pos->common.session, session, sizeof(pos->common.session)) != 0)
|
| 345 | continue;
|
| 346 |
|
| 347 | |
| 348 | * process..it makes sense to pay more when the session is
|
| 349 | * finished and to speed the process up during the measurement
|
| 350 |
|
| 351 | if (unlikely(!kref_get_unless_zero(&pos->common.refcount)))
|
| 352 | continue;
|
| 353 |
|
| 354 | tp_vars = pos;
|
| 355 | break;
|
| 356 | }
|
| 357 | rcu_read_unlock();
|
| 358 |
|
| 359 | return tp_vars;
|
| 360 | }
|
| 361 |
|
| 362 | |
| 363 | * batadv_tp_sender_release() - release batadv_tp_sender
|
| 364 | * and queue for free after rcu grace period
|
| 365 | * @ref: kref pointer of the batadv_tp_sender
|
| 366 |
|
| 367 | static void batadv_tp_sender_release(struct kref *ref)
|
| 368 | {
|
| 369 | struct batadv_tp_sender *tp_vars;
|
| 370 |
|
| 371 | tp_vars = container_of(ref, struct batadv_tp_sender, common.refcount);
|
| 372 | kfree_rcu(tp_vars, common.rcu);
|
| 373 | }
|
| 374 |
|
| 375 | |
| 376 | * batadv_tp_sender_put() - decrement the batadv_tp_sender
|
| 377 | * refcounter and possibly release it
|
| 378 | * @tp_vars: the private data of the current TP meter session to be free'd
|
| 379 |
|
| 380 | static void batadv_tp_sender_put(struct batadv_tp_sender *tp_vars)
|
| 381 | {
|
| 382 | if (!tp_vars)
|
| 383 | return;
|
| 384 |
|
| 385 | kref_put(&tp_vars->common.refcount, batadv_tp_sender_release);
|
| 386 | }
|
| 387 |
|
| 388 | |
| 389 | * batadv_tp_list_detach() - remove tp session from mesh session list once
|
| 390 | * @tp_vars: the private data of the current TP meter session
|
| 391 | *
|
| 392 | * Return: whether tp_vars was detached from list and reference must be freed
|
| 393 |
|
| 394 | static bool batadv_tp_list_detach(struct batadv_tp_vars_common *tp_vars)
|
| 395 | {
|
| 396 | bool detached = false;
|
| 397 |
|
| 398 | spin_lock_bh(&tp_vars->bat_priv->tp_list_lock);
|
| 399 | if (!hlist_unhashed(&tp_vars->list)) {
|
| 400 | hlist_del_init_rcu(&tp_vars->list);
|
| 401 | detached = true;
|
| 402 | }
|
| 403 | spin_unlock_bh(&tp_vars->bat_priv->tp_list_lock);
|
| 404 |
|
| 405 | if (!detached)
|
| 406 | return false;
|
| 407 |
|
| 408 | atomic_dec(&tp_vars->bat_priv->tp_num);
|
| 409 |
|
| 410 | return true;
|
| 411 | }
|
| 412 |
|
| 413 | |
| 414 | * batadv_tp_sender_cleanup() - cleanup sender data and drop and timer
|
| 415 | * @tp_vars: the private data of the current TP meter session to cleanup
|
| 416 |
|
| 417 | static void batadv_tp_sender_cleanup(struct batadv_tp_sender *tp_vars)
|
| 418 | {
|
| 419 | disable_delayed_work_sync(&tp_vars->finish_work);
|
| 420 |
|
| 421 | if (batadv_tp_list_detach(&tp_vars->common))
|
| 422 | batadv_tp_sender_put(tp_vars);
|
| 423 |
|
| 424 |
|
| 425 | timer_shutdown_sync(&tp_vars->common.timer);
|
| 426 | batadv_tp_sender_put(tp_vars);
|
| 427 | }
|
| 428 |
|
| 429 | |
| 430 | * batadv_tp_sender_end() - print info about ended session and inform client
|
| 431 | * @bat_priv: the bat priv with all the mesh interface information
|
| 432 | * @tp_vars: the private data of the current TP meter session
|
| 433 |
|
| 434 | static void batadv_tp_sender_end(struct batadv_priv *bat_priv,
|
| 435 | struct batadv_tp_sender *tp_vars)
|
| 436 | {
|
| 437 | enum batadv_tp_meter_reason reason;
|
| 438 | u32 session_cookie;
|
| 439 |
|
| 440 | reason = atomic_read(&tp_vars->send_result);
|
| 441 |
|
| 442 | batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
|
| 443 | "Test towards %pM finished..shutting down (reason=%d)\n",
|
| 444 | tp_vars->common.other_end, reason);
|
| 445 |
|
| 446 | batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
|
| 447 | "Last timing stats: SRTT=%ums RTTVAR=%ums RTO=%ums\n",
|
| 448 | tp_vars->cc.srtt >> 3, tp_vars->cc.rttvar >> 2, tp_vars->cc.rto);
|
| 449 |
|
| 450 | batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
|
| 451 | "Final values: cwnd=%u ss_threshold=%u\n",
|
| 452 | tp_vars->cc.cwnd, tp_vars->cc.ss_threshold);
|
| 453 |
|
| 454 | session_cookie = batadv_tp_session_cookie(tp_vars->common.session,
|
| 455 | tp_vars->icmp_uid);
|
| 456 |
|
| 457 | batadv_tp_batctl_notify(reason,
|
| 458 | tp_vars->common.other_end,
|
| 459 | bat_priv,
|
| 460 | tp_vars->start_time,
|
| 461 | atomic64_read(&tp_vars->tot_sent),
|
| 462 | session_cookie);
|
| 463 | }
|
| 464 |
|
| 465 | |
| 466 | * batadv_tp_sender_shutdown() - let sender thread/timer stop gracefully
|
| 467 | * @tp_vars: the private data of the current TP meter session
|
| 468 | * @reason: reason for tp meter session stop
|
| 469 |
|
| 470 | static void batadv_tp_sender_shutdown(struct batadv_tp_sender *tp_vars,
|
| 471 | enum batadv_tp_meter_reason reason)
|
| 472 | {
|
| 473 | atomic_cmpxchg(&tp_vars->send_result, 0, reason);
|
| 474 | }
|
| 475 |
|
| 476 | |
| 477 | * batadv_tp_sender_stopped() - check if tp session was stopped with reason
|
| 478 | * @tp_vars: the private data of the current TP meter session
|
| 479 | *
|
| 480 | * Return: whether stop reason was found
|
| 481 |
|
| 482 | static bool batadv_tp_sender_stopped(struct batadv_tp_sender *tp_vars)
|
| 483 | {
|
| 484 | return atomic_read(&tp_vars->send_result) != 0;
|
| 485 | }
|
| 486 |
|
| 487 | |
| 488 | * batadv_tp_sender_finish() - stop sender session after test_length was reached
|
| 489 | * @work: delayed work reference of the related tp_vars
|
| 490 |
|
| 491 | static void batadv_tp_sender_finish(struct work_struct *work)
|
| 492 | {
|
| 493 | struct delayed_work *delayed_work;
|
| 494 | struct batadv_tp_sender *tp_vars;
|
| 495 |
|
| 496 | delayed_work = to_delayed_work(work);
|
| 497 | tp_vars = container_of(delayed_work, struct batadv_tp_sender,
|
| 498 | finish_work);
|
| 499 |
|
| 500 | batadv_tp_sender_shutdown(tp_vars, BATADV_TP_REASON_COMPLETE);
|
| 501 | }
|
| 502 |
|
| 503 | |
| 504 | * batadv_tp_reset_sender_timer() - reschedule the sender timer
|
| 505 | * @tp_vars: the private TP meter data for this session
|
| 506 | *
|
| 507 | * Reschedule the timer using tp_vars->cc.rto as delay
|
| 508 |
|
| 509 | static void batadv_tp_reset_sender_timer(struct batadv_tp_sender *tp_vars)
|
| 510 | {
|
| 511 | |
| 512 | * reception...
|
| 513 |
|
| 514 | if (unlikely(batadv_tp_sender_stopped(tp_vars)))
|
| 515 |
|
| 516 | return;
|
| 517 |
|
| 518 | mod_timer(&tp_vars->common.timer,
|
| 519 | jiffies + msecs_to_jiffies(READ_ONCE(tp_vars->cc.rto)));
|
| 520 | }
|
| 521 |
|
| 522 | |
| 523 | * batadv_tp_sender_timeout() - timer that fires in case of packet loss
|
| 524 | * @t: address to timer_list inside tp_vars
|
| 525 | *
|
| 526 | * If fired it means that there was packet loss.
|
| 527 | * Switch to Slow Start, set the ss_threshold to half of the current cwnd and
|
| 528 | * reset the cwnd to 3*MSS
|
| 529 |
|
| 530 | static void batadv_tp_sender_timeout(struct timer_list *t)
|
| 531 | {
|
| 532 | struct batadv_tp_sender *tp_vars = timer_container_of(tp_vars, t, common.timer);
|
| 533 | struct batadv_priv *bat_priv = tp_vars->common.bat_priv;
|
| 534 |
|
| 535 | if (batadv_tp_sender_stopped(tp_vars))
|
| 536 | return;
|
| 537 |
|
| 538 | spin_lock_bh(&tp_vars->cc_lock);
|
| 539 |
|
| 540 |
|
| 541 | if (unlikely(tp_vars->cc.rto >= BATADV_TP_MAX_RTO)) {
|
| 542 | spin_unlock_bh(&tp_vars->cc_lock);
|
| 543 | batadv_tp_sender_shutdown(tp_vars,
|
| 544 | BATADV_TP_REASON_DST_UNREACHABLE);
|
| 545 | return;
|
| 546 | }
|
| 547 |
|
| 548 | |
| 549 | * Details in Section 5.5 of RFC6298
|
| 550 |
|
| 551 | WRITE_ONCE(tp_vars->cc.rto, tp_vars->cc.rto * 2);
|
| 552 |
|
| 553 | tp_vars->cc.ss_threshold = tp_vars->cc.cwnd >> 1;
|
| 554 | if (tp_vars->cc.ss_threshold < BATADV_TP_PLEN * 2)
|
| 555 | tp_vars->cc.ss_threshold = BATADV_TP_PLEN * 2;
|
| 556 |
|
| 557 | batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
|
| 558 | "Meter: RTO fired during test towards %pM! cwnd=%u new ss_thr=%u, resetting last_sent to %u\n",
|
| 559 | tp_vars->common.other_end, tp_vars->cc.cwnd, tp_vars->cc.ss_threshold,
|
| 560 | tp_vars->cc.last_acked);
|
| 561 |
|
| 562 | tp_vars->cc.cwnd = BATADV_TP_PLEN * 3;
|
| 563 |
|
| 564 | WRITE_ONCE(tp_vars->cc.last_sent, tp_vars->cc.last_acked);
|
| 565 |
|
| 566 | spin_unlock_bh(&tp_vars->cc_lock);
|
| 567 |
|
| 568 |
|
| 569 | wake_up(&tp_vars->more_bytes);
|
| 570 |
|
| 571 | batadv_tp_reset_sender_timer(tp_vars);
|
| 572 | }
|
| 573 |
|
| 574 | |
| 575 | * batadv_tp_fill_prerandom() - Fill buffer with prefetched random bytes
|
| 576 | * @tp_vars: the private TP meter data for this session
|
| 577 | * @buf: Buffer to fill with bytes
|
| 578 | * @nbytes: amount of pseudorandom bytes
|
| 579 |
|
| 580 | static void batadv_tp_fill_prerandom(struct batadv_tp_sender *tp_vars,
|
| 581 | u8 *buf, size_t nbytes)
|
| 582 | {
|
| 583 | size_t bytes_inbuf;
|
| 584 | u32 local_offset;
|
| 585 | size_t to_copy;
|
| 586 | size_t pos = 0;
|
| 587 |
|
| 588 | spin_lock_bh(&tp_vars->prerandom_lock);
|
| 589 | local_offset = tp_vars->prerandom_offset;
|
| 590 | tp_vars->prerandom_offset += nbytes;
|
| 591 | tp_vars->prerandom_offset %= sizeof(batadv_tp_prerandom);
|
| 592 | spin_unlock_bh(&tp_vars->prerandom_lock);
|
| 593 |
|
| 594 | while (nbytes) {
|
| 595 | local_offset %= sizeof(batadv_tp_prerandom);
|
| 596 | bytes_inbuf = sizeof(batadv_tp_prerandom) - local_offset;
|
| 597 | to_copy = min(nbytes, bytes_inbuf);
|
| 598 |
|
| 599 | memcpy(&buf[pos], &batadv_tp_prerandom[local_offset], to_copy);
|
| 600 | pos += to_copy;
|
| 601 | nbytes -= to_copy;
|
| 602 | local_offset = 0;
|
| 603 | }
|
| 604 | }
|
| 605 |
|
| 606 | |
| 607 | * batadv_tp_send_msg() - send a single message
|
| 608 | * @tp_vars: the private TP meter data for this session
|
| 609 | * @src: source mac address
|
| 610 | * @orig_node: the originator of the destination
|
| 611 | * @seqno: sequence number of this packet
|
| 612 | * @len: length of the entire packet
|
| 613 | * @session: session identifier
|
| 614 | * @uid: local ICMP "socket" index
|
| 615 | * @timestamp: timestamp in jiffies which is replied in ack
|
| 616 | *
|
| 617 | * Create and send a single TP Meter message.
|
| 618 | *
|
| 619 | * Return: 0 on success, BATADV_TP_REASON_MEMORY_ERROR if the packet couldn't
|
| 620 | * be allocated, BATADV_TP_REASON_CANT_SEND if the packet could not be
|
| 621 | * transmitted
|
| 622 |
|
| 623 | static int batadv_tp_send_msg(struct batadv_tp_sender *tp_vars, const u8 *src,
|
| 624 | struct batadv_orig_node *orig_node,
|
| 625 | u32 seqno, size_t len, const u8 *session,
|
| 626 | int uid, u32 timestamp)
|
| 627 | {
|
| 628 | struct batadv_icmp_tp_packet *icmp;
|
| 629 | struct sk_buff *skb;
|
| 630 | size_t data_len;
|
| 631 | u8 *data;
|
| 632 | int r;
|
| 633 |
|
| 634 | skb = netdev_alloc_skb_ip_align(NULL, len + ETH_HLEN);
|
| 635 | if (unlikely(!skb))
|
| 636 | return BATADV_TP_REASON_MEMORY_ERROR;
|
| 637 |
|
| 638 | skb_reserve(skb, ETH_HLEN);
|
| 639 | icmp = skb_put(skb, sizeof(*icmp));
|
| 640 |
|
| 641 |
|
| 642 | ether_addr_copy(icmp->dst, orig_node->orig);
|
| 643 | ether_addr_copy(icmp->orig, src);
|
| 644 | icmp->version = BATADV_COMPAT_VERSION;
|
| 645 | icmp->packet_type = BATADV_ICMP;
|
| 646 | icmp->ttl = BATADV_TTL;
|
| 647 | icmp->msg_type = BATADV_TP;
|
| 648 | icmp->uid = uid;
|
| 649 |
|
| 650 | icmp->subtype = BATADV_TP_MSG;
|
| 651 | memcpy(icmp->session, session, sizeof(icmp->session));
|
| 652 | icmp->seqno = htonl(seqno);
|
| 653 | icmp->timestamp = htonl(timestamp);
|
| 654 |
|
| 655 | data_len = len - sizeof(*icmp);
|
| 656 | data = skb_put(skb, data_len);
|
| 657 | batadv_tp_fill_prerandom(tp_vars, data, data_len);
|
| 658 |
|
| 659 | r = batadv_send_skb_to_orig(skb, orig_node, NULL);
|
| 660 | if (r == NET_XMIT_SUCCESS)
|
| 661 | return 0;
|
| 662 |
|
| 663 | return BATADV_TP_REASON_CANT_SEND;
|
| 664 | }
|
| 665 |
|
| 666 | |
| 667 | * enum batadv_tp_ack_reaction - expected reaction to ack packet
|
| 668 |
|
| 669 | enum batadv_tp_ack_reaction {
|
| 670 |
|
| 671 | BATADV_TP_ACK_REACTION_OLD_ACK,
|
| 672 |
|
| 673 |
|
| 674 | BATADV_TP_ACK_REACTION_IGNORE,
|
| 675 |
|
| 676 |
|
| 677 | BATADV_TP_ACK_REACTION_RESEND_WAKEUP,
|
| 678 |
|
| 679 |
|
| 680 | BATADV_TP_ACK_REACTION_WAKEUP,
|
| 681 | };
|
| 682 |
|
| 683 | |
| 684 | * batadv_tp_handle_ack() - Calculate reaction to ACK and update congestion control
|
| 685 | * @bat_priv: the bat priv with all the mesh interface information
|
| 686 | * @tp_vars: the private data of the current TP meter session
|
| 687 | * @recv_ack: received ACK seqno
|
| 688 | * @mss: maximum segment size for transmission
|
| 689 | *
|
| 690 | * Return: expected reaction to this ack
|
| 691 |
|
| 692 | static enum batadv_tp_ack_reaction
|
| 693 | batadv_tp_handle_ack(struct batadv_priv *bat_priv,
|
| 694 | struct batadv_tp_sender *tp_vars,
|
| 695 | u32 recv_ack, size_t mss)
|
| 696 | __must_hold(&tp_vars->cc_lock)
|
| 697 | {
|
| 698 | enum batadv_tp_ack_reaction reaction;
|
| 699 |
|
| 700 | if (batadv_seq_before(recv_ack, tp_vars->cc.last_acked))
|
| 701 | return BATADV_TP_ACK_REACTION_OLD_ACK;
|
| 702 |
|
| 703 |
|
| 704 | if (tp_vars->cc.last_acked == recv_ack) {
|
| 705 |
|
| 706 | if (tp_vars->cc.dup_acks > 3)
|
| 707 | return BATADV_TP_ACK_REACTION_IGNORE;
|
| 708 |
|
| 709 | tp_vars->cc.dup_acks++;
|
| 710 | if (tp_vars->cc.dup_acks != 3)
|
| 711 | return BATADV_TP_ACK_REACTION_IGNORE;
|
| 712 |
|
| 713 | if (!batadv_seq_before(tp_vars->cc.recover, recv_ack))
|
| 714 | return BATADV_TP_ACK_REACTION_IGNORE;
|
| 715 |
|
| 716 |
|
| 717 | tp_vars->cc.fast_recovery = true;
|
| 718 |
|
| 719 | |
| 720 | * is entered. RFC6582, Section 3.2, step 1
|
| 721 |
|
| 722 | tp_vars->cc.recover = tp_vars->cc.last_sent;
|
| 723 | tp_vars->cc.ss_threshold = tp_vars->cc.cwnd >> 1;
|
| 724 | batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
|
| 725 | "Meter: Fast Recovery, (cur cwnd=%u) ss_thr=%u last_sent=%u recv_ack=%u\n",
|
| 726 | tp_vars->cc.cwnd, tp_vars->cc.ss_threshold,
|
| 727 | tp_vars->cc.last_sent, recv_ack);
|
| 728 | tp_vars->cc.cwnd = batadv_tp_cwnd(tp_vars->cc.ss_threshold, 3 * mss,
|
| 729 | mss);
|
| 730 | tp_vars->cc.dec_cwnd = 0;
|
| 731 | WRITE_ONCE(tp_vars->cc.last_sent, recv_ack);
|
| 732 |
|
| 733 | return BATADV_TP_ACK_REACTION_RESEND_WAKEUP;
|
| 734 | }
|
| 735 |
|
| 736 |
|
| 737 | atomic64_add(recv_ack - tp_vars->cc.last_acked, &tp_vars->tot_sent);
|
| 738 |
|
| 739 |
|
| 740 | tp_vars->cc.dup_acks = 0;
|
| 741 |
|
| 742 | if (tp_vars->cc.fast_recovery) {
|
| 743 |
|
| 744 | if (batadv_seq_before(recv_ack, tp_vars->cc.recover)) {
|
| 745 | |
| 746 | * immediately as specified by NewReno (see
|
| 747 | * Section 3.2 of RFC6582 for details)
|
| 748 |
|
| 749 | reaction = BATADV_TP_ACK_REACTION_RESEND_WAKEUP;
|
| 750 | tp_vars->cc.cwnd = batadv_tp_cwnd(tp_vars->cc.cwnd,
|
| 751 | mss, mss);
|
| 752 | } else {
|
| 753 | tp_vars->cc.fast_recovery = false;
|
| 754 | |
| 755 | * moment that Fast Recovery was entered.
|
| 756 | * RFC6582, Section 3.2, step 3
|
| 757 |
|
| 758 | tp_vars->cc.cwnd = batadv_tp_cwnd(tp_vars->cc.ss_threshold,
|
| 759 | 0, mss);
|
| 760 | reaction = BATADV_TP_ACK_REACTION_WAKEUP;
|
| 761 | }
|
| 762 | } else {
|
| 763 | if (recv_ack - tp_vars->cc.last_acked >= mss)
|
| 764 | batadv_tp_update_cwnd(tp_vars, mss);
|
| 765 |
|
| 766 | reaction = BATADV_TP_ACK_REACTION_WAKEUP;
|
| 767 | }
|
| 768 |
|
| 769 |
|
| 770 | WRITE_ONCE(tp_vars->cc.last_acked, recv_ack);
|
| 771 |
|
| 772 | return reaction;
|
| 773 | }
|
| 774 |
|
| 775 | |
| 776 | * batadv_tp_recv_ack() - ACK receiving function
|
| 777 | * @bat_priv: the bat priv with all the mesh interface information
|
| 778 | * @skb: the buffer containing the received packet
|
| 779 | *
|
| 780 | * Process a received TP ACK packet
|
| 781 |
|
| 782 | static void batadv_tp_recv_ack(struct batadv_priv *bat_priv,
|
| 783 | const struct sk_buff *skb)
|
| 784 | {
|
| 785 | struct batadv_hard_iface *primary_if = NULL;
|
| 786 | struct batadv_orig_node *orig_node = NULL;
|
| 787 | const struct batadv_icmp_tp_packet *icmp;
|
| 788 | enum batadv_tp_ack_reaction reaction;
|
| 789 | struct batadv_tp_sender *tp_vars;
|
| 790 | size_t packet_len;
|
| 791 | u32 recv_ack;
|
| 792 | size_t mss;
|
| 793 | u32 rtt;
|
| 794 |
|
| 795 | packet_len = BATADV_TP_PLEN;
|
| 796 | mss = BATADV_TP_PLEN;
|
| 797 | packet_len += sizeof(struct batadv_unicast_packet);
|
| 798 |
|
| 799 | icmp = (struct batadv_icmp_tp_packet *)skb->data;
|
| 800 | recv_ack = ntohl(icmp->seqno);
|
| 801 |
|
| 802 |
|
| 803 | tp_vars = batadv_tp_list_find_sender_session(bat_priv, icmp->orig,
|
| 804 | icmp->session);
|
| 805 | if (unlikely(!tp_vars))
|
| 806 | return;
|
| 807 |
|
| 808 | if (unlikely(batadv_tp_sender_stopped(tp_vars)))
|
| 809 | goto out;
|
| 810 |
|
| 811 |
|
| 812 | if (batadv_seq_before(recv_ack, READ_ONCE(tp_vars->cc.last_acked)))
|
| 813 | goto out;
|
| 814 |
|
| 815 | primary_if = batadv_primary_if_get_selected(bat_priv);
|
| 816 | if (unlikely(!primary_if))
|
| 817 | goto out;
|
| 818 |
|
| 819 | orig_node = batadv_orig_hash_find(bat_priv, icmp->orig);
|
| 820 | if (unlikely(!orig_node))
|
| 821 | goto out;
|
| 822 |
|
| 823 | spin_lock_bh(&tp_vars->cc_lock);
|
| 824 |
|
| 825 | rtt = jiffies_to_msecs(jiffies) - ntohl(icmp->timestamp);
|
| 826 | if (icmp->timestamp && rtt)
|
| 827 | batadv_tp_update_rto(tp_vars, rtt);
|
| 828 |
|
| 829 | reaction = batadv_tp_handle_ack(bat_priv, tp_vars, recv_ack, mss);
|
| 830 | spin_unlock_bh(&tp_vars->cc_lock);
|
| 831 |
|
| 832 | if (reaction == BATADV_TP_ACK_REACTION_OLD_ACK)
|
| 833 | goto out;
|
| 834 |
|
| 835 |
|
| 836 | batadv_tp_reset_sender_timer(tp_vars);
|
| 837 |
|
| 838 | switch (reaction) {
|
| 839 | default:
|
| 840 | case BATADV_TP_ACK_REACTION_IGNORE:
|
| 841 | goto out;
|
| 842 | case BATADV_TP_ACK_REACTION_RESEND_WAKEUP:
|
| 843 | batadv_tp_send_msg(tp_vars, primary_if->net_dev->dev_addr,
|
| 844 | orig_node, recv_ack, packet_len,
|
| 845 | icmp->session, icmp->uid,
|
| 846 | jiffies_to_msecs(jiffies));
|
| 847 | fallthrough;
|
| 848 | case BATADV_TP_ACK_REACTION_WAKEUP:
|
| 849 | wake_up(&tp_vars->more_bytes);
|
| 850 | break;
|
| 851 | }
|
| 852 |
|
| 853 | out:
|
| 854 | batadv_hardif_put(primary_if);
|
| 855 | batadv_orig_node_put(orig_node);
|
| 856 | batadv_tp_sender_put(tp_vars);
|
| 857 | }
|
| 858 |
|
| 859 | |
| 860 | * batadv_tp_avail() - check if congestion window is not full
|
| 861 | * @tp_vars: the private data of the current TP meter session
|
| 862 | * @payload_len: size of the payload of a single message
|
| 863 | *
|
| 864 | * Return: true when congestion window is not full, false otherwise
|
| 865 |
|
| 866 | static bool batadv_tp_avail(struct batadv_tp_sender *tp_vars,
|
| 867 | size_t payload_len)
|
| 868 | {
|
| 869 | u32 win_limit;
|
| 870 | u32 win_left;
|
| 871 |
|
| 872 | spin_lock_bh(&tp_vars->cc_lock);
|
| 873 |
|
| 874 | win_limit = tp_vars->cc.last_acked + tp_vars->cc.cwnd;
|
| 875 |
|
| 876 | if (batadv_seq_before(tp_vars->cc.last_sent, win_limit))
|
| 877 | win_left = win_limit - tp_vars->cc.last_sent;
|
| 878 | else
|
| 879 | win_left = 0;
|
| 880 |
|
| 881 | spin_unlock_bh(&tp_vars->cc_lock);
|
| 882 |
|
| 883 | return win_left >= payload_len;
|
| 884 | }
|
| 885 |
|
| 886 | |
| 887 | * batadv_tp_wait_available() - wait until congestion window becomes free or
|
| 888 | * timeout is reached
|
| 889 | * @tp_vars: the private data of the current TP meter session
|
| 890 | * @plen: size of the payload of a single message
|
| 891 | *
|
| 892 | * Return: 0 if the condition evaluated to false after the timeout elapsed,
|
| 893 | * 1 if the condition evaluated to true after the timeout elapsed, the
|
| 894 | * remaining jiffies (at least 1) if the condition evaluated to true before
|
| 895 | * the timeout elapsed, or -ERESTARTSYS if it was interrupted by a signal.
|
| 896 |
|
| 897 | static int batadv_tp_wait_available(struct batadv_tp_sender *tp_vars, size_t plen)
|
| 898 | {
|
| 899 | int ret;
|
| 900 |
|
| 901 | ret = wait_event_interruptible_timeout(tp_vars->more_bytes,
|
| 902 | batadv_tp_avail(tp_vars, plen),
|
| 903 | HZ / 10);
|
| 904 |
|
| 905 | return ret;
|
| 906 | }
|
| 907 |
|
| 908 | |
| 909 | * batadv_tp_send() - main sending thread of a tp meter session
|
| 910 | * @arg: address of the related tp_vars
|
| 911 | *
|
| 912 | * Return: 0
|
| 913 |
|
| 914 | static int batadv_tp_send(void *arg)
|
| 915 | {
|
| 916 | struct batadv_hard_iface *primary_if = NULL;
|
| 917 | struct batadv_orig_node *orig_node = NULL;
|
| 918 | struct batadv_tp_sender *tp_vars = arg;
|
| 919 | struct batadv_priv *bat_priv;
|
| 920 | size_t payload_len;
|
| 921 | size_t packet_len;
|
| 922 | u32 last_sent;
|
| 923 | int err = 0;
|
| 924 |
|
| 925 | bat_priv = tp_vars->common.bat_priv;
|
| 926 | orig_node = batadv_orig_hash_find(bat_priv, tp_vars->common.other_end);
|
| 927 | if (unlikely(!orig_node)) {
|
| 928 | err = BATADV_TP_REASON_DST_UNREACHABLE;
|
| 929 | batadv_tp_sender_shutdown(tp_vars, err);
|
| 930 | goto out;
|
| 931 | }
|
| 932 |
|
| 933 | primary_if = batadv_primary_if_get_selected(bat_priv);
|
| 934 | if (unlikely(!primary_if)) {
|
| 935 | err = BATADV_TP_REASON_DST_UNREACHABLE;
|
| 936 | batadv_tp_sender_shutdown(tp_vars, err);
|
| 937 | goto out;
|
| 938 | }
|
| 939 |
|
| 940 | |
| 941 | * configured MTU, so use the mesh_iface MTU as MSS.
|
| 942 | * This might not be true and in that case the fragmentation
|
| 943 | * should be used.
|
| 944 | * Now, try to send the packet as it is
|
| 945 |
|
| 946 | payload_len = BATADV_TP_PLEN;
|
| 947 | BUILD_BUG_ON(sizeof(struct batadv_icmp_tp_packet) > BATADV_TP_PLEN);
|
| 948 |
|
| 949 | batadv_tp_reset_sender_timer(tp_vars);
|
| 950 |
|
| 951 |
|
| 952 | queue_delayed_work(batadv_event_workqueue, &tp_vars->finish_work,
|
| 953 | msecs_to_jiffies(tp_vars->test_length));
|
| 954 |
|
| 955 | while (!batadv_tp_sender_stopped(tp_vars)) {
|
| 956 | if (unlikely(!batadv_tp_avail(tp_vars, payload_len))) {
|
| 957 | batadv_tp_wait_available(tp_vars, payload_len);
|
| 958 | continue;
|
| 959 | }
|
| 960 |
|
| 961 | |
| 962 | * the size of the unicast header
|
| 963 |
|
| 964 | packet_len = payload_len + sizeof(struct batadv_unicast_packet);
|
| 965 | last_sent = READ_ONCE(tp_vars->cc.last_sent);
|
| 966 |
|
| 967 | err = batadv_tp_send_msg(tp_vars, primary_if->net_dev->dev_addr,
|
| 968 | orig_node, last_sent, packet_len,
|
| 969 | tp_vars->common.session, tp_vars->icmp_uid,
|
| 970 | jiffies_to_msecs(jiffies));
|
| 971 |
|
| 972 |
|
| 973 | if (unlikely(err && err != BATADV_TP_REASON_CANT_SEND)) {
|
| 974 | batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
|
| 975 | "Meter: %s() cannot send packets (%d)\n",
|
| 976 | __func__, err);
|
| 977 |
|
| 978 | batadv_tp_sender_shutdown(tp_vars, err);
|
| 979 | break;
|
| 980 | }
|
| 981 |
|
| 982 |
|
| 983 | if (!err) {
|
| 984 | spin_lock_bh(&tp_vars->cc_lock);
|
| 985 | if (tp_vars->cc.last_sent == last_sent)
|
| 986 | WRITE_ONCE(tp_vars->cc.last_sent, last_sent + payload_len);
|
| 987 | spin_unlock_bh(&tp_vars->cc_lock);
|
| 988 | }
|
| 989 |
|
| 990 | cond_resched();
|
| 991 | }
|
| 992 |
|
| 993 | out:
|
| 994 | batadv_hardif_put(primary_if);
|
| 995 | batadv_orig_node_put(orig_node);
|
| 996 |
|
| 997 | batadv_tp_sender_end(bat_priv, tp_vars);
|
| 998 | batadv_tp_sender_cleanup(tp_vars);
|
| 999 | complete(&tp_vars->finished);
|
| 1000 |
|
| 1001 | batadv_tp_sender_put(tp_vars);
|
| 1002 |
|
| 1003 | return 0;
|
| 1004 | }
|
| 1005 |
|
| 1006 | |
| 1007 | * batadv_tp_start_kthread() - start new thread which manages the tp meter
|
| 1008 | * sender
|
| 1009 | * @tp_vars: the private data of the current TP meter session
|
| 1010 |
|
| 1011 | static void batadv_tp_start_kthread(struct batadv_tp_sender *tp_vars)
|
| 1012 | {
|
| 1013 | struct batadv_priv *bat_priv = tp_vars->common.bat_priv;
|
| 1014 | struct task_struct *kthread;
|
| 1015 | u32 session_cookie;
|
| 1016 |
|
| 1017 | kref_get(&tp_vars->common.refcount);
|
| 1018 | kthread = kthread_create(batadv_tp_send, tp_vars, "kbatadv_tp_meter");
|
| 1019 | if (IS_ERR(kthread)) {
|
| 1020 | session_cookie = batadv_tp_session_cookie(tp_vars->common.session,
|
| 1021 | tp_vars->icmp_uid);
|
| 1022 | pr_err("batadv: cannot create tp meter kthread\n");
|
| 1023 | batadv_tp_batctl_error_notify(BATADV_TP_REASON_MEMORY_ERROR,
|
| 1024 | tp_vars->common.other_end,
|
| 1025 | bat_priv, session_cookie);
|
| 1026 |
|
| 1027 |
|
| 1028 | batadv_tp_sender_put(tp_vars);
|
| 1029 |
|
| 1030 |
|
| 1031 | batadv_tp_sender_cleanup(tp_vars);
|
| 1032 | complete(&tp_vars->finished);
|
| 1033 | return;
|
| 1034 | }
|
| 1035 |
|
| 1036 | wake_up_process(kthread);
|
| 1037 | }
|
| 1038 |
|
| 1039 | |
| 1040 | * batadv_tp_start() - start a new tp meter session
|
| 1041 | * @bat_priv: the bat priv with all the mesh interface information
|
| 1042 | * @dst: the receiver MAC address
|
| 1043 | * @test_length: test length in milliseconds
|
| 1044 | * @cookie: session cookie
|
| 1045 |
|
| 1046 | void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
|
| 1047 | u32 test_length, u32 *cookie)
|
| 1048 | {
|
| 1049 | struct batadv_tp_sender *tp_vars;
|
| 1050 | u32 session_cookie;
|
| 1051 | u8 session_id[2];
|
| 1052 | u8 icmp_uid;
|
| 1053 |
|
| 1054 | get_random_bytes(session_id, sizeof(session_id));
|
| 1055 | get_random_bytes(&icmp_uid, 1);
|
| 1056 | session_cookie = batadv_tp_session_cookie(session_id, icmp_uid);
|
| 1057 | *cookie = session_cookie;
|
| 1058 |
|
| 1059 |
|
| 1060 | spin_lock_bh(&bat_priv->tp_list_lock);
|
| 1061 | if (READ_ONCE(bat_priv->mesh_state) != BATADV_MESH_ACTIVE) {
|
| 1062 | spin_unlock_bh(&bat_priv->tp_list_lock);
|
| 1063 | batadv_tp_batctl_error_notify(BATADV_TP_REASON_DST_UNREACHABLE,
|
| 1064 | dst, bat_priv, session_cookie);
|
| 1065 | return;
|
| 1066 | }
|
| 1067 |
|
| 1068 | if (batadv_tp_list_active(bat_priv, dst)) {
|
| 1069 | spin_unlock_bh(&bat_priv->tp_list_lock);
|
| 1070 | batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
|
| 1071 | "Meter: test to or from the same node already ongoing, aborting\n");
|
| 1072 | batadv_tp_batctl_error_notify(BATADV_TP_REASON_ALREADY_ONGOING,
|
| 1073 | dst, bat_priv, session_cookie);
|
| 1074 | return;
|
| 1075 | }
|
| 1076 |
|
| 1077 | if (!atomic_add_unless(&bat_priv->tp_num, 1, BATADV_TP_MAX_NUM)) {
|
| 1078 | spin_unlock_bh(&bat_priv->tp_list_lock);
|
| 1079 | batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
|
| 1080 | "Meter: too many ongoing sessions, aborting (SEND)\n");
|
| 1081 | batadv_tp_batctl_error_notify(BATADV_TP_REASON_TOO_MANY, dst,
|
| 1082 | bat_priv, session_cookie);
|
| 1083 | return;
|
| 1084 | }
|
| 1085 |
|
| 1086 | tp_vars = kmalloc_obj(*tp_vars, GFP_ATOMIC);
|
| 1087 | if (!tp_vars) {
|
| 1088 | atomic_dec(&bat_priv->tp_num);
|
| 1089 | spin_unlock_bh(&bat_priv->tp_list_lock);
|
| 1090 | batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
|
| 1091 | "Meter: %s cannot allocate list elements\n",
|
| 1092 | __func__);
|
| 1093 | batadv_tp_batctl_error_notify(BATADV_TP_REASON_MEMORY_ERROR,
|
| 1094 | dst, bat_priv, session_cookie);
|
| 1095 | return;
|
| 1096 | }
|
| 1097 |
|
| 1098 |
|
| 1099 | ether_addr_copy(tp_vars->common.other_end, dst);
|
| 1100 | kref_init(&tp_vars->common.refcount);
|
| 1101 | atomic_set(&tp_vars->send_result, 0);
|
| 1102 | memcpy(tp_vars->common.session, session_id, sizeof(session_id));
|
| 1103 | tp_vars->icmp_uid = icmp_uid;
|
| 1104 |
|
| 1105 | WRITE_ONCE(tp_vars->cc.last_sent, BATADV_TP_FIRST_SEQ);
|
| 1106 | WRITE_ONCE(tp_vars->cc.dup_acks, 0);
|
| 1107 | WRITE_ONCE(tp_vars->cc.last_acked, BATADV_TP_FIRST_SEQ);
|
| 1108 | tp_vars->cc.fast_recovery = false;
|
| 1109 | tp_vars->cc.recover = BATADV_TP_FIRST_SEQ;
|
| 1110 |
|
| 1111 | |
| 1112 | * For batman-adv the MSS is the size of the payload received by the
|
| 1113 | * mesh_interface, hence its MTU
|
| 1114 |
|
| 1115 | tp_vars->cc.cwnd = BATADV_TP_PLEN * 3;
|
| 1116 | tp_vars->cc.dec_cwnd = 0;
|
| 1117 |
|
| 1118 | |
| 1119 | * window size, hence the AWND size
|
| 1120 |
|
| 1121 | tp_vars->cc.ss_threshold = BATADV_TP_AWND;
|
| 1122 |
|
| 1123 | |
| 1124 | * Details in Section 2.1 of RFC6298
|
| 1125 |
|
| 1126 | WRITE_ONCE(tp_vars->cc.rto, 1000);
|
| 1127 | tp_vars->cc.srtt = 0;
|
| 1128 | tp_vars->cc.rttvar = 0;
|
| 1129 |
|
| 1130 | atomic64_set(&tp_vars->tot_sent, 0);
|
| 1131 |
|
| 1132 | kref_get(&tp_vars->common.refcount);
|
| 1133 | timer_setup(&tp_vars->common.timer, batadv_tp_sender_timeout, 0);
|
| 1134 |
|
| 1135 | tp_vars->common.bat_priv = bat_priv;
|
| 1136 | tp_vars->start_time = jiffies;
|
| 1137 |
|
| 1138 | init_waitqueue_head(&tp_vars->more_bytes);
|
| 1139 | init_completion(&tp_vars->finished);
|
| 1140 |
|
| 1141 | spin_lock_init(&tp_vars->cc_lock);
|
| 1142 |
|
| 1143 | tp_vars->prerandom_offset = 0;
|
| 1144 | spin_lock_init(&tp_vars->prerandom_lock);
|
| 1145 |
|
| 1146 | tp_vars->test_length = test_length;
|
| 1147 | if (!tp_vars->test_length)
|
| 1148 | tp_vars->test_length = BATADV_TP_DEF_TEST_LENGTH;
|
| 1149 |
|
| 1150 |
|
| 1151 | INIT_DELAYED_WORK(&tp_vars->finish_work, batadv_tp_sender_finish);
|
| 1152 |
|
| 1153 | kref_get(&tp_vars->common.refcount);
|
| 1154 | hlist_add_head_rcu(&tp_vars->common.list, &bat_priv->tp_sender_list);
|
| 1155 | spin_unlock_bh(&bat_priv->tp_list_lock);
|
| 1156 |
|
| 1157 | batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
|
| 1158 | "Meter: starting throughput meter towards %pM (length=%ums)\n",
|
| 1159 | dst, test_length);
|
| 1160 |
|
| 1161 | |
| 1162 | * happily return and avoid to block
|
| 1163 |
|
| 1164 | batadv_tp_start_kthread(tp_vars);
|
| 1165 |
|
| 1166 |
|
| 1167 | batadv_tp_sender_put(tp_vars);
|
| 1168 | }
|
| 1169 |
|
| 1170 | |
| 1171 | * batadv_tp_stop() - stop currently running tp meter session
|
| 1172 | * @bat_priv: the bat priv with all the mesh interface information
|
| 1173 | * @dst: the receiver MAC address
|
| 1174 | * @return_value: reason for tp meter session stop
|
| 1175 |
|
| 1176 | void batadv_tp_stop(struct batadv_priv *bat_priv, const u8 *dst,
|
| 1177 | u8 return_value)
|
| 1178 | {
|
| 1179 | struct batadv_orig_node *orig_node;
|
| 1180 | struct batadv_tp_sender *tp_vars;
|
| 1181 |
|
| 1182 | batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
|
| 1183 | "Meter: stopping test towards %pM\n", dst);
|
| 1184 |
|
| 1185 | orig_node = batadv_orig_hash_find(bat_priv, dst);
|
| 1186 | if (!orig_node)
|
| 1187 | return;
|
| 1188 |
|
| 1189 | tp_vars = batadv_tp_list_find_sender(bat_priv, orig_node->orig);
|
| 1190 | if (!tp_vars) {
|
| 1191 | batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
|
| 1192 | "Meter: trying to interrupt an already over connection\n");
|
| 1193 | goto out_put_orig_node;
|
| 1194 | }
|
| 1195 |
|
| 1196 | batadv_tp_sender_shutdown(tp_vars, return_value);
|
| 1197 | batadv_tp_sender_put(tp_vars);
|
| 1198 | out_put_orig_node:
|
| 1199 | batadv_orig_node_put(orig_node);
|
| 1200 | }
|
| 1201 |
|
| 1202 | |
| 1203 | * batadv_tp_list_find_receiver_session() - find tp_vars receiver session
|
| 1204 | * object in the global list
|
| 1205 | * @bat_priv: the bat priv with all the mesh interface information
|
| 1206 | * @dst: the other endpoint MAC address to look for
|
| 1207 | * @session: session identifier
|
| 1208 | *
|
| 1209 | * Look for a tp_vars object matching dst as end_point, session as tp meter
|
| 1210 | * session and return it after having increment the refcounter. Return NULL
|
| 1211 | * is not found
|
| 1212 | *
|
| 1213 | * Return: matching tp_vars or NULL when no tp_vars was found
|
| 1214 |
|
| 1215 | static struct batadv_tp_receiver *
|
| 1216 | batadv_tp_list_find_receiver_session(struct batadv_priv *bat_priv, const u8 *dst,
|
| 1217 | const u8 *session)
|
| 1218 | {
|
| 1219 | struct batadv_tp_receiver *tp_vars = NULL;
|
| 1220 | struct batadv_tp_receiver *pos;
|
| 1221 |
|
| 1222 | rcu_read_lock();
|
| 1223 | hlist_for_each_entry_rcu(pos, &bat_priv->tp_receiver_list, common.list) {
|
| 1224 | if (!batadv_compare_eth(pos->common.other_end, dst))
|
| 1225 | continue;
|
| 1226 |
|
| 1227 | if (memcmp(pos->common.session, session, sizeof(pos->common.session)) != 0)
|
| 1228 | continue;
|
| 1229 |
|
| 1230 | |
| 1231 | * process..it makes sense to pay more when the session is
|
| 1232 | * finished and to speed the process up during the measurement
|
| 1233 |
|
| 1234 | if (unlikely(!kref_get_unless_zero(&pos->common.refcount)))
|
| 1235 | continue;
|
| 1236 |
|
| 1237 | tp_vars = pos;
|
| 1238 | break;
|
| 1239 | }
|
| 1240 | rcu_read_unlock();
|
| 1241 |
|
| 1242 | return tp_vars;
|
| 1243 | }
|
| 1244 |
|
| 1245 | |
| 1246 | * batadv_tp_receiver_release() - release batadv_tp_receiver
|
| 1247 | * and queue for free after rcu grace period
|
| 1248 | * @ref: kref pointer of the batadv_tp_receiver
|
| 1249 |
|
| 1250 | static void batadv_tp_receiver_release(struct kref *ref)
|
| 1251 | {
|
| 1252 | struct batadv_tp_receiver *tp_vars;
|
| 1253 | struct batadv_tp_unacked *safe;
|
| 1254 | struct batadv_tp_unacked *un;
|
| 1255 |
|
| 1256 | tp_vars = container_of(ref, struct batadv_tp_receiver, common.refcount);
|
| 1257 |
|
| 1258 | |
| 1259 | * context!
|
| 1260 |
|
| 1261 | spin_lock_bh(&tp_vars->ack_seqno_lock);
|
| 1262 | list_for_each_entry_safe(un, safe, &tp_vars->unacked_list, list) {
|
| 1263 | list_del(&un->list);
|
| 1264 | kfree(un);
|
| 1265 | tp_vars->unacked_count--;
|
| 1266 | }
|
| 1267 | spin_unlock_bh(&tp_vars->ack_seqno_lock);
|
| 1268 |
|
| 1269 | kfree_rcu(tp_vars, common.rcu);
|
| 1270 | }
|
| 1271 |
|
| 1272 | |
| 1273 | * batadv_tp_receiver_put() - decrement the batadv_tp_receiver
|
| 1274 | * refcounter and possibly release it
|
| 1275 | * @tp_vars: the private data of the current TP meter session to be free'd
|
| 1276 |
|
| 1277 | static void batadv_tp_receiver_put(struct batadv_tp_receiver *tp_vars)
|
| 1278 | {
|
| 1279 | if (!tp_vars)
|
| 1280 | return;
|
| 1281 |
|
| 1282 | kref_put(&tp_vars->common.refcount, batadv_tp_receiver_release);
|
| 1283 | }
|
| 1284 |
|
| 1285 | |
| 1286 | * batadv_tp_reset_receiver_timer() - reset the receiver shutdown timer
|
| 1287 | * @tp_vars: the private data of the current TP meter session
|
| 1288 | *
|
| 1289 | * start the receiver shutdown timer or reset it if already started
|
| 1290 |
|
| 1291 | static void batadv_tp_reset_receiver_timer(struct batadv_tp_receiver *tp_vars)
|
| 1292 | {
|
| 1293 | mod_timer(&tp_vars->common.timer,
|
| 1294 | jiffies + msecs_to_jiffies(BATADV_TP_RECV_TIMEOUT));
|
| 1295 | }
|
| 1296 |
|
| 1297 | |
| 1298 | * batadv_tp_receiver_shutdown() - stop a tp meter receiver when timeout is
|
| 1299 | * reached without received ack
|
| 1300 | * @t: address to timer_list inside tp_vars
|
| 1301 |
|
| 1302 | static void batadv_tp_receiver_shutdown(struct timer_list *t)
|
| 1303 | {
|
| 1304 | struct batadv_tp_receiver *tp_vars = timer_container_of(tp_vars, t, common.timer);
|
| 1305 | struct batadv_tp_unacked *safe;
|
| 1306 | struct batadv_tp_unacked *un;
|
| 1307 | struct batadv_priv *bat_priv;
|
| 1308 |
|
| 1309 | bat_priv = tp_vars->common.bat_priv;
|
| 1310 |
|
| 1311 |
|
| 1312 | if (!batadv_has_timed_out(READ_ONCE(tp_vars->last_recv_time),
|
| 1313 | BATADV_TP_RECV_TIMEOUT)) {
|
| 1314 |
|
| 1315 | batadv_tp_reset_receiver_timer(tp_vars);
|
| 1316 | return;
|
| 1317 | }
|
| 1318 |
|
| 1319 | batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
|
| 1320 | "Shutting down for inactivity (more than %dms) from %pM\n",
|
| 1321 | BATADV_TP_RECV_TIMEOUT, tp_vars->common.other_end);
|
| 1322 |
|
| 1323 | if (batadv_tp_list_detach(&tp_vars->common))
|
| 1324 | batadv_tp_receiver_put(tp_vars);
|
| 1325 |
|
| 1326 | spin_lock_bh(&tp_vars->ack_seqno_lock);
|
| 1327 | list_for_each_entry_safe(un, safe, &tp_vars->unacked_list, list) {
|
| 1328 | list_del(&un->list);
|
| 1329 | kfree(un);
|
| 1330 | tp_vars->unacked_count--;
|
| 1331 | }
|
| 1332 | spin_unlock_bh(&tp_vars->ack_seqno_lock);
|
| 1333 |
|
| 1334 |
|
| 1335 | if (WARN_ON(atomic_xchg(&tp_vars->receiving, 0) != 1))
|
| 1336 | return;
|
| 1337 |
|
| 1338 | batadv_tp_receiver_put(tp_vars);
|
| 1339 | }
|
| 1340 |
|
| 1341 | |
| 1342 | * batadv_tp_send_ack() - send an ACK packet
|
| 1343 | * @bat_priv: the bat priv with all the mesh interface information
|
| 1344 | * @dst: the mac address of the destination originator
|
| 1345 | * @seq: the sequence number to ACK
|
| 1346 | * @timestamp: the timestamp to echo back in the ACK
|
| 1347 | * @session: session identifier
|
| 1348 | * @socket_index: local ICMP socket identifier
|
| 1349 | *
|
| 1350 | * Return: 0 on success, a positive integer representing the reason of the
|
| 1351 | * failure otherwise
|
| 1352 |
|
| 1353 | static int batadv_tp_send_ack(struct batadv_priv *bat_priv, const u8 *dst,
|
| 1354 | u32 seq, __be32 timestamp, const u8 *session,
|
| 1355 | int socket_index)
|
| 1356 | {
|
| 1357 | struct batadv_hard_iface *primary_if = NULL;
|
| 1358 | struct batadv_orig_node *orig_node;
|
| 1359 | struct batadv_icmp_tp_packet *icmp;
|
| 1360 | struct sk_buff *skb;
|
| 1361 | int ret;
|
| 1362 | int r;
|
| 1363 |
|
| 1364 | orig_node = batadv_orig_hash_find(bat_priv, dst);
|
| 1365 | if (unlikely(!orig_node)) {
|
| 1366 | ret = BATADV_TP_REASON_DST_UNREACHABLE;
|
| 1367 | goto out;
|
| 1368 | }
|
| 1369 |
|
| 1370 | primary_if = batadv_primary_if_get_selected(bat_priv);
|
| 1371 | if (unlikely(!primary_if)) {
|
| 1372 | ret = BATADV_TP_REASON_DST_UNREACHABLE;
|
| 1373 | goto out;
|
| 1374 | }
|
| 1375 |
|
| 1376 | skb = netdev_alloc_skb_ip_align(NULL, sizeof(*icmp) + ETH_HLEN);
|
| 1377 | if (unlikely(!skb)) {
|
| 1378 | ret = BATADV_TP_REASON_MEMORY_ERROR;
|
| 1379 | goto out;
|
| 1380 | }
|
| 1381 |
|
| 1382 | skb_reserve(skb, ETH_HLEN);
|
| 1383 | icmp = skb_put(skb, sizeof(*icmp));
|
| 1384 | icmp->packet_type = BATADV_ICMP;
|
| 1385 | icmp->version = BATADV_COMPAT_VERSION;
|
| 1386 | icmp->ttl = BATADV_TTL;
|
| 1387 | icmp->msg_type = BATADV_TP;
|
| 1388 | ether_addr_copy(icmp->dst, orig_node->orig);
|
| 1389 | ether_addr_copy(icmp->orig, primary_if->net_dev->dev_addr);
|
| 1390 | icmp->uid = socket_index;
|
| 1391 |
|
| 1392 | icmp->subtype = BATADV_TP_ACK;
|
| 1393 | memcpy(icmp->session, session, sizeof(icmp->session));
|
| 1394 | icmp->seqno = htonl(seq);
|
| 1395 | icmp->timestamp = timestamp;
|
| 1396 |
|
| 1397 |
|
| 1398 | r = batadv_send_skb_to_orig(skb, orig_node, NULL);
|
| 1399 | if (unlikely(r < 0) || r == NET_XMIT_DROP) {
|
| 1400 | ret = BATADV_TP_REASON_DST_UNREACHABLE;
|
| 1401 | goto out;
|
| 1402 | }
|
| 1403 | ret = 0;
|
| 1404 |
|
| 1405 | out:
|
| 1406 | batadv_orig_node_put(orig_node);
|
| 1407 | batadv_hardif_put(primary_if);
|
| 1408 |
|
| 1409 | return ret;
|
| 1410 | }
|
| 1411 |
|
| 1412 | |
| 1413 | * batadv_tp_handle_out_of_order() - store an out of order packet
|
| 1414 | * @tp_vars: the private data of the current TP meter session
|
| 1415 | * @seqno: sequence number of new received packet
|
| 1416 | * @payload_len: length of the received packet
|
| 1417 | *
|
| 1418 | * Store the out of order packet in the unacked list for late processing. This
|
| 1419 | * packets are kept in this list so that they can be ACKed at once as soon as
|
| 1420 | * all the previous packets have been received
|
| 1421 | *
|
| 1422 | * Return: true if the packed has been successfully processed, false otherwise
|
| 1423 |
|
| 1424 | static bool batadv_tp_handle_out_of_order(struct batadv_tp_receiver *tp_vars,
|
| 1425 | u32 seqno, u32 payload_len)
|
| 1426 | __must_hold(&tp_vars->ack_seqno_lock)
|
| 1427 | {
|
| 1428 | struct list_head *pos = &tp_vars->unacked_list;
|
| 1429 | struct batadv_tp_unacked *new = NULL;
|
| 1430 | u32 end_seqno = seqno + payload_len;
|
| 1431 | struct batadv_tp_unacked *safe;
|
| 1432 | struct batadv_tp_unacked *un;
|
| 1433 |
|
| 1434 | |
| 1435 | * seqno range can be merged with or the position at which a new entry
|
| 1436 | * has to be inserted.
|
| 1437 | *
|
| 1438 | * The iteration is done in the reverse way because it is likely that
|
| 1439 | * the last received packet (the one being processed now) has a bigger
|
| 1440 | * seqno than all the others already stored.
|
| 1441 |
|
| 1442 | list_for_each_entry_reverse(un, &tp_vars->unacked_list, list) {
|
| 1443 |
|
| 1444 | if (batadv_seq_before(seqno, un->seqno))
|
| 1445 | continue;
|
| 1446 |
|
| 1447 | |
| 1448 | * after another or overlapping. keep only a single entry
|
| 1449 | *
|
| 1450 | * It is already known that:
|
| 1451 | *
|
| 1452 | * un->seqno <= seqno
|
| 1453 | *
|
| 1454 | * When establishing that:
|
| 1455 | *
|
| 1456 | * seqno <= un->seqno + un->len
|
| 1457 | *
|
| 1458 | * Then it is not necessary to add a new entry because the
|
| 1459 | * smaller/equal seqno of un might already contain the new
|
| 1460 | * received packet or we only add new data directly after
|
| 1461 | * the end of un. The latter can be identified using:
|
| 1462 | *
|
| 1463 | * un->seqno + un->len <= end_seqno
|
| 1464 |
|
| 1465 | if (!batadv_seq_before(un->seqno + un->len, seqno)) {
|
| 1466 |
|
| 1467 | if (!batadv_seq_before(end_seqno, un->seqno + un->len))
|
| 1468 | un->len = end_seqno - un->seqno;
|
| 1469 |
|
| 1470 | |
| 1471 | * be used to check if the gap to the next seqno range
|
| 1472 | * was closed
|
| 1473 |
|
| 1474 | new = un;
|
| 1475 | } else {
|
| 1476 | |
| 1477 | * the new one is attached _after_ it. In this way the
|
| 1478 | * list is kept in ascending order
|
| 1479 |
|
| 1480 | pos = &un->list;
|
| 1481 | }
|
| 1482 |
|
| 1483 | break;
|
| 1484 | }
|
| 1485 |
|
| 1486 | |
| 1487 | * with the next smaller seqno (or at the front of the list when the
|
| 1488 | * new seqno is the smallest or the list is empty)
|
| 1489 |
|
| 1490 | if (!new) {
|
| 1491 | new = kmalloc_obj(*new, GFP_ATOMIC);
|
| 1492 | if (unlikely(!new))
|
| 1493 | return false;
|
| 1494 |
|
| 1495 | new->seqno = seqno;
|
| 1496 | new->len = payload_len;
|
| 1497 |
|
| 1498 | list_add(&new->list, pos);
|
| 1499 | tp_vars->unacked_count++;
|
| 1500 | }
|
| 1501 |
|
| 1502 |
|
| 1503 | un = new;
|
| 1504 | list_for_each_entry_safe_continue(un, safe, &tp_vars->unacked_list, list) {
|
| 1505 | if (batadv_seq_before(end_seqno, un->seqno))
|
| 1506 | break;
|
| 1507 |
|
| 1508 |
|
| 1509 | if (batadv_seq_before(end_seqno, un->seqno + un->len)) {
|
| 1510 | end_seqno = un->seqno + un->len;
|
| 1511 | new->len = end_seqno - new->seqno;
|
| 1512 | }
|
| 1513 |
|
| 1514 | list_del(&un->list);
|
| 1515 | kfree(un);
|
| 1516 | tp_vars->unacked_count--;
|
| 1517 | }
|
| 1518 |
|
| 1519 |
|
| 1520 | if (tp_vars->unacked_count > BATADV_TP_MAX_UNACKED) {
|
| 1521 | un = list_last_entry(&tp_vars->unacked_list,
|
| 1522 | struct batadv_tp_unacked, list);
|
| 1523 | list_del(&un->list);
|
| 1524 | kfree(un);
|
| 1525 | tp_vars->unacked_count--;
|
| 1526 | }
|
| 1527 |
|
| 1528 | return true;
|
| 1529 | }
|
| 1530 |
|
| 1531 | |
| 1532 | * batadv_tp_ack_unordered() - update number received bytes in current stream
|
| 1533 | * without gaps
|
| 1534 | * @tp_vars: the private data of the current TP meter session
|
| 1535 |
|
| 1536 | static void batadv_tp_ack_unordered(struct batadv_tp_receiver *tp_vars)
|
| 1537 | __must_hold(&tp_vars->ack_seqno_lock)
|
| 1538 | {
|
| 1539 | struct batadv_tp_unacked *safe;
|
| 1540 | struct batadv_tp_unacked *un;
|
| 1541 | u32 to_ack;
|
| 1542 |
|
| 1543 | |
| 1544 | * well
|
| 1545 |
|
| 1546 | list_for_each_entry_safe(un, safe, &tp_vars->unacked_list, list) {
|
| 1547 | |
| 1548 | * there is a gap between the last acked seqno and the seqno of
|
| 1549 | * the packet under inspection
|
| 1550 |
|
| 1551 | if (batadv_seq_before(tp_vars->last_recv, un->seqno))
|
| 1552 | break;
|
| 1553 |
|
| 1554 | to_ack = un->seqno + un->len;
|
| 1555 |
|
| 1556 | if (batadv_seq_before(tp_vars->last_recv, to_ack))
|
| 1557 | tp_vars->last_recv = to_ack;
|
| 1558 |
|
| 1559 | list_del(&un->list);
|
| 1560 | kfree(un);
|
| 1561 | tp_vars->unacked_count--;
|
| 1562 | }
|
| 1563 | }
|
| 1564 |
|
| 1565 | |
| 1566 | * batadv_tp_init_recv() - return matching or create new receiver tp_vars
|
| 1567 | * @bat_priv: the bat priv with all the mesh interface information
|
| 1568 | * @icmp: received icmp tp msg
|
| 1569 | *
|
| 1570 | * Return: corresponding tp_vars or NULL on errors
|
| 1571 |
|
| 1572 | static struct batadv_tp_receiver *
|
| 1573 | batadv_tp_init_recv(struct batadv_priv *bat_priv,
|
| 1574 | const struct batadv_icmp_tp_packet *icmp)
|
| 1575 | {
|
| 1576 | struct batadv_tp_receiver *tp_vars = NULL;
|
| 1577 |
|
| 1578 | spin_lock_bh(&bat_priv->tp_list_lock);
|
| 1579 | if (READ_ONCE(bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
|
| 1580 | goto out_unlock;
|
| 1581 |
|
| 1582 | tp_vars = batadv_tp_list_find_receiver_session(bat_priv, icmp->orig,
|
| 1583 | icmp->session);
|
| 1584 | if (tp_vars) {
|
| 1585 | WRITE_ONCE(tp_vars->last_recv_time, jiffies);
|
| 1586 | goto out_unlock;
|
| 1587 | }
|
| 1588 |
|
| 1589 | if (!atomic_add_unless(&bat_priv->tp_num, 1, BATADV_TP_MAX_NUM)) {
|
| 1590 | batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
|
| 1591 | "Meter: too many ongoing sessions, aborting (RECV)\n");
|
| 1592 | goto out_unlock;
|
| 1593 | }
|
| 1594 |
|
| 1595 | tp_vars = kmalloc_obj(*tp_vars, GFP_ATOMIC);
|
| 1596 | if (!tp_vars) {
|
| 1597 | atomic_dec(&bat_priv->tp_num);
|
| 1598 | goto out_unlock;
|
| 1599 | }
|
| 1600 |
|
| 1601 | ether_addr_copy(tp_vars->common.other_end, icmp->orig);
|
| 1602 | atomic_set(&tp_vars->receiving, 1);
|
| 1603 | memcpy(tp_vars->common.session, icmp->session, sizeof(tp_vars->common.session));
|
| 1604 | tp_vars->last_recv = BATADV_TP_FIRST_SEQ;
|
| 1605 | tp_vars->common.bat_priv = bat_priv;
|
| 1606 | kref_init(&tp_vars->common.refcount);
|
| 1607 |
|
| 1608 | spin_lock_init(&tp_vars->ack_seqno_lock);
|
| 1609 | INIT_LIST_HEAD(&tp_vars->unacked_list);
|
| 1610 | tp_vars->unacked_count = 0;
|
| 1611 |
|
| 1612 | kref_get(&tp_vars->common.refcount);
|
| 1613 | timer_setup(&tp_vars->common.timer, batadv_tp_receiver_shutdown, 0);
|
| 1614 |
|
| 1615 | WRITE_ONCE(tp_vars->last_recv_time, jiffies);
|
| 1616 |
|
| 1617 | kref_get(&tp_vars->common.refcount);
|
| 1618 | hlist_add_head_rcu(&tp_vars->common.list, &bat_priv->tp_receiver_list);
|
| 1619 |
|
| 1620 | batadv_tp_reset_receiver_timer(tp_vars);
|
| 1621 |
|
| 1622 | out_unlock:
|
| 1623 | spin_unlock_bh(&bat_priv->tp_list_lock);
|
| 1624 |
|
| 1625 | return tp_vars;
|
| 1626 | }
|
| 1627 |
|
| 1628 | |
| 1629 | * batadv_tp_recv_msg() - process a single data message
|
| 1630 | * @bat_priv: the bat priv with all the mesh interface information
|
| 1631 | * @skb: the buffer containing the received packet
|
| 1632 | *
|
| 1633 | * Process a received TP MSG packet
|
| 1634 |
|
| 1635 | static void batadv_tp_recv_msg(struct batadv_priv *bat_priv,
|
| 1636 | const struct sk_buff *skb)
|
| 1637 | {
|
| 1638 | const struct batadv_icmp_tp_packet *icmp;
|
| 1639 | struct batadv_tp_receiver *tp_vars;
|
| 1640 | u32 payload_len;
|
| 1641 | u32 to_ack;
|
| 1642 | u32 seqno;
|
| 1643 |
|
| 1644 | icmp = (struct batadv_icmp_tp_packet *)skb->data;
|
| 1645 |
|
| 1646 | seqno = ntohl(icmp->seqno);
|
| 1647 | |
| 1648 | * first packet is lost, the tp meter does not work anymore!
|
| 1649 |
|
| 1650 | if (seqno == BATADV_TP_FIRST_SEQ) {
|
| 1651 | tp_vars = batadv_tp_init_recv(bat_priv, icmp);
|
| 1652 | if (!tp_vars) {
|
| 1653 | batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
|
| 1654 | "Meter: seqno != BATADV_TP_FIRST_SEQ cannot initiate connection\n");
|
| 1655 | goto out;
|
| 1656 | }
|
| 1657 | } else {
|
| 1658 | tp_vars = batadv_tp_list_find_receiver_session(bat_priv, icmp->orig,
|
| 1659 | icmp->session);
|
| 1660 | if (!tp_vars) {
|
| 1661 | batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
|
| 1662 | "Unexpected packet from %pM!\n",
|
| 1663 | icmp->orig);
|
| 1664 | goto out;
|
| 1665 | }
|
| 1666 |
|
| 1667 | WRITE_ONCE(tp_vars->last_recv_time, jiffies);
|
| 1668 | }
|
| 1669 |
|
| 1670 | spin_lock_bh(&tp_vars->ack_seqno_lock);
|
| 1671 |
|
| 1672 | |
| 1673 | * lost. Resend the ACK
|
| 1674 |
|
| 1675 | payload_len = skb->len - sizeof(struct batadv_unicast_packet);
|
| 1676 | to_ack = seqno + payload_len;
|
| 1677 | if (batadv_seq_before(to_ack, tp_vars->last_recv))
|
| 1678 | goto send_ack;
|
| 1679 |
|
| 1680 |
|
| 1681 | if (batadv_seq_before(tp_vars->last_recv, seqno)) {
|
| 1682 | |
| 1683 | * not been enqueued correctly
|
| 1684 |
|
| 1685 | if (!batadv_tp_handle_out_of_order(tp_vars, seqno, payload_len)) {
|
| 1686 | spin_unlock_bh(&tp_vars->ack_seqno_lock);
|
| 1687 | goto out;
|
| 1688 | }
|
| 1689 |
|
| 1690 |
|
| 1691 | goto send_ack;
|
| 1692 | }
|
| 1693 |
|
| 1694 |
|
| 1695 | tp_vars->last_recv = to_ack;
|
| 1696 |
|
| 1697 |
|
| 1698 | batadv_tp_ack_unordered(tp_vars);
|
| 1699 |
|
| 1700 | send_ack:
|
| 1701 | to_ack = tp_vars->last_recv;
|
| 1702 | spin_unlock_bh(&tp_vars->ack_seqno_lock);
|
| 1703 |
|
| 1704 | |
| 1705 | * is going to be sent is a duplicate (the sender will count them and
|
| 1706 | * possibly enter Fast Retransmit as soon as it has reached 3)
|
| 1707 |
|
| 1708 | batadv_tp_send_ack(bat_priv, icmp->orig, to_ack,
|
| 1709 | icmp->timestamp, icmp->session, icmp->uid);
|
| 1710 | out:
|
| 1711 | batadv_tp_receiver_put(tp_vars);
|
| 1712 | }
|
| 1713 |
|
| 1714 | |
| 1715 | * batadv_tp_meter_recv() - main TP Meter receiving function
|
| 1716 | * @bat_priv: the bat priv with all the mesh interface information
|
| 1717 | * @skb: the buffer containing the received packet
|
| 1718 |
|
| 1719 | void batadv_tp_meter_recv(struct batadv_priv *bat_priv, struct sk_buff *skb)
|
| 1720 | {
|
| 1721 | struct batadv_icmp_tp_packet *icmp;
|
| 1722 |
|
| 1723 | if (READ_ONCE(bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
|
| 1724 | goto out;
|
| 1725 |
|
| 1726 | icmp = (struct batadv_icmp_tp_packet *)skb->data;
|
| 1727 |
|
| 1728 | switch (icmp->subtype) {
|
| 1729 | case BATADV_TP_MSG:
|
| 1730 | batadv_tp_recv_msg(bat_priv, skb);
|
| 1731 | break;
|
| 1732 | case BATADV_TP_ACK:
|
| 1733 | batadv_tp_recv_ack(bat_priv, skb);
|
| 1734 | break;
|
| 1735 | default:
|
| 1736 | batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
|
| 1737 | "Received unknown TP Metric packet type %u\n",
|
| 1738 | icmp->subtype);
|
| 1739 | }
|
| 1740 |
|
| 1741 | out:
|
| 1742 | consume_skb(skb);
|
| 1743 | }
|
| 1744 |
|
| 1745 | |
| 1746 | * batadv_tp_stop_all() - stop all currently running tp meter sessions
|
| 1747 | * @bat_priv: the bat priv with all the mesh interface information
|
| 1748 |
|
| 1749 | void batadv_tp_stop_all(struct batadv_priv *bat_priv)
|
| 1750 | {
|
| 1751 | struct batadv_tp_receiver *tp_receivers[BATADV_TP_MAX_NUM];
|
| 1752 | struct batadv_tp_sender *tp_senders[BATADV_TP_MAX_NUM];
|
| 1753 | struct batadv_tp_receiver *tp_receiver;
|
| 1754 | struct batadv_tp_sender *tp_sender;
|
| 1755 | size_t receiver_count = 0;
|
| 1756 | size_t sender_count = 0;
|
| 1757 | size_t i;
|
| 1758 |
|
| 1759 | spin_lock_bh(&bat_priv->tp_list_lock);
|
| 1760 | hlist_for_each_entry(tp_receiver, &bat_priv->tp_receiver_list, common.list) {
|
| 1761 | if (WARN_ON_ONCE(receiver_count >= BATADV_TP_MAX_NUM))
|
| 1762 | break;
|
| 1763 |
|
| 1764 | if (!kref_get_unless_zero(&tp_receiver->common.refcount))
|
| 1765 | continue;
|
| 1766 |
|
| 1767 | tp_receivers[receiver_count++] = tp_receiver;
|
| 1768 | }
|
| 1769 |
|
| 1770 | hlist_for_each_entry(tp_sender, &bat_priv->tp_sender_list, common.list) {
|
| 1771 | if (WARN_ON_ONCE(sender_count >= BATADV_TP_MAX_NUM))
|
| 1772 | break;
|
| 1773 |
|
| 1774 | if (!kref_get_unless_zero(&tp_sender->common.refcount))
|
| 1775 | continue;
|
| 1776 |
|
| 1777 | tp_senders[sender_count++] = tp_sender;
|
| 1778 | }
|
| 1779 | spin_unlock_bh(&bat_priv->tp_list_lock);
|
| 1780 |
|
| 1781 | for (i = 0; i < receiver_count; i++) {
|
| 1782 | tp_receiver = tp_receivers[i];
|
| 1783 |
|
| 1784 | if (batadv_tp_list_detach(&tp_receiver->common))
|
| 1785 | batadv_tp_receiver_put(tp_receiver);
|
| 1786 |
|
| 1787 | timer_shutdown_sync(&tp_receiver->common.timer);
|
| 1788 |
|
| 1789 | if (atomic_xchg(&tp_receiver->receiving, 0) != 0)
|
| 1790 | batadv_tp_receiver_put(tp_receiver);
|
| 1791 |
|
| 1792 | batadv_tp_receiver_put(tp_receiver);
|
| 1793 | }
|
| 1794 |
|
| 1795 | for (i = 0; i < sender_count; i++) {
|
| 1796 | tp_sender = tp_senders[i];
|
| 1797 |
|
| 1798 | batadv_tp_sender_shutdown(tp_sender, BATADV_TP_REASON_CANCEL);
|
| 1799 | wake_up(&tp_sender->more_bytes);
|
| 1800 | wait_for_completion(&tp_sender->finished);
|
| 1801 |
|
| 1802 | batadv_tp_sender_put(tp_sender);
|
| 1803 | }
|
| 1804 |
|
| 1805 | synchronize_net();
|
| 1806 | }
|
| 1807 |
|
| 1808 | |
| 1809 | * batadv_tp_meter_init() - initialize global tp_meter structures
|
| 1810 |
|
| 1811 | void __init batadv_tp_meter_init(void)
|
| 1812 | {
|
| 1813 | get_random_bytes(batadv_tp_prerandom, sizeof(batadv_tp_prerandom));
|
| 1814 | }
|