Cumulative patch from commit 12c1fdf19a721aaf29e1c77d63445c7f5b8c61c0

12c1fdf P2P: Update peer listen channel from Probe Request frames
a805731 P2P: Abort ongoing scan when p2p_find is stopped
7441698 nl80211: Abort an ongoing scan upon scan timeout indication
1446afc wpa_supplicant: Handle EVENT_SCAN_RESULTS when an interface is disabled
d14e63a WNM: Do not scan based on malformed BSS Transition Management Request
f420577 WNM: Fix candidates count in BSS Transition Management Request
3c58df7 wpa_cli: Support running action script on global control interface
b8f02d8 EAP-PWD peer: Fix possible memory leak on error path
8f38eed Android: Remove superfluous OpenSSL include paths
cbf8d18 HS 2.0R2: Clear fetch_anqp_in_progress if fopen fails
4a6e9e5 Fix CONFIG_WPA_TRACE=y compilation without CONFIG_WPA_TRACE_BFD=y
2bf9a53 Add EAP-AKA' and EAP-pwd to wpa_supplicant README
4196c08 Update notes about OpenSSL versions
5d7b1a3 Fix some typos in wpa_supplicant README files
4194fee README-P2P: Fix a typo
c58eed6 P2P: Add Dev Info attribute to Probe Request frames in 60 GHz
2b6e9f9 wpa_supplicant: Expose wpas_get_bands() and related API
94ad3c3 P2P: Change order of P2P IE and frequencies set up
61697c7 Android: Allow wpa_supplicant to write files to osu-info dir
0147afa FST: Enlarge State Transition Timeout (STT)
e1d00d4 Add error handling for offloaded ACS with vendor command failures
bef5e9a Fix scan rescheduling from wpas_stop_pno to check postponed case
b9ca12a nl80211: Add more address fields into RX frame debug message
debde14 RADIUS: Add Acct-Delay-Time into accounting messages
669b532 RADIUS: Update full message for interim accounting updates
251953b Document nas_identifier requirements for RADIUS accounting
902c07a Replace hostapd_mac_comp_empty() with is_zero_ether_addr()
5aef495 VLAN: Avoid use of libnl cache
732b1d2 nl80211: Clean up ifidx properly if interface in a bridge is removed
170c545 FT: Check destination MAC address on RRB receive
57b2c91 RADIUS: Allow RADIUS server to provide PSK instead of passphrase
d8912fd Cache hashed passphrase in RADIUS-based PSK delivery
f8e09bc Defer passphrase-to-PSK hashing out of 802.11 authentication ACL check
cc9c805 VLAN: Use stack instead of heap allocation for new interface name
d48d1b8 FT: Use BSSID as r1_key_holder if no value is configured
71456db FT: Check hapd->wpa_auth before RRB internal delivery
0270bde FT: Fix R0KH-R1KH protocol data length values
96a26ab P2P: Support dedicated P2P_DEVICE without separate group interface
ba307f8 P2P: Add a separate pointer to the P2P Device instance
e040197 GAS client: Make PMF check on RX more consistent
0645492 WNM: Optimize a single BSS transition management candidate scan
eb20cea nl80211: Add an option to specify the BSSID to scan for
adf0478 AP: Store STA supported operating classes information

Change-Id: If0ce28aae5591be783c38e5b60f7f9ff0fb9f8f2
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index b24bbf8..a4edd5f 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -226,6 +226,16 @@
 	 * next_radius_identifier - Next RADIUS message identifier to use
 	 */
 	u8 next_radius_identifier;
+
+	/**
+	 * interim_error_cb - Interim accounting error callback
+	 */
+	void (*interim_error_cb)(const u8 *addr, void *ctx);
+
+	/**
+	 * interim_error_cb_ctx - interim_error_cb() context data
+	 */
+	void *interim_error_cb_ctx;
 };
 
 
@@ -297,6 +307,25 @@
 }
 
 
+/**
+ * radius_client_set_interim_erro_cb - Register an interim acct error callback
+ * @radius: RADIUS client context from radius_client_init()
+ * @addr: Station address from the failed message
+ * @cb: Handler for interim accounting errors
+ * @ctx: Context pointer for handler callbacks
+ *
+ * This function is used to register a handler for processing failed
+ * transmission attempts of interim accounting update messages.
+ */
+void radius_client_set_interim_error_cb(struct radius_client_data *radius,
+					void (*cb)(const u8 *addr, void *ctx),
+					void *ctx)
+{
+	radius->interim_error_cb = cb;
+	radius->interim_error_cb_ctx = ctx;
+}
+
+
 /*
  * Returns >0 if message queue was flushed (i.e., the message that triggered
  * the error is not available anymore)
@@ -336,6 +365,8 @@
 	int s;
 	struct wpabuf *buf;
 	size_t prev_num_msgs;
+	u8 *acct_delay_time;
+	size_t acct_delay_time_len;
 
 	if (entry->msg_type == RADIUS_ACCT ||
 	    entry->msg_type == RADIUS_ACCT_INTERIM) {
@@ -371,12 +402,52 @@
 			conf->auth_server->retransmissions++;
 		}
 	}
+
+	if (entry->msg_type == RADIUS_ACCT_INTERIM) {
+		wpa_printf(MSG_DEBUG,
+			   "RADIUS: Failed to transmit interim accounting update to "
+			   MACSTR " - drop message and request a new update",
+			   MAC2STR(entry->addr));
+		if (radius->interim_error_cb)
+			radius->interim_error_cb(entry->addr,
+						 radius->interim_error_cb_ctx);
+		return 1;
+	}
+
 	if (s < 0) {
 		wpa_printf(MSG_INFO,
 			   "RADIUS: No valid socket for retransmission");
 		return 1;
 	}
 
+	if (entry->msg_type == RADIUS_ACCT &&
+	    radius_msg_get_attr_ptr(entry->msg, RADIUS_ATTR_ACCT_DELAY_TIME,
+				    &acct_delay_time, &acct_delay_time_len,
+				    NULL) == 0 &&
+	    acct_delay_time_len == 4) {
+		struct radius_hdr *hdr;
+		u32 delay_time;
+
+		/*
+		 * Need to assign a new identifier since attribute contents
+		 * changes.
+		 */
+		hdr = radius_msg_get_hdr(entry->msg);
+		hdr->identifier = radius_client_get_id(radius);
+
+		/* Update Acct-Delay-Time to show wait time in queue */
+		delay_time = now - entry->first_try;
+		WPA_PUT_BE32(acct_delay_time, delay_time);
+
+		wpa_printf(MSG_DEBUG,
+			   "RADIUS: Updated Acct-Delay-Time to %u for retransmission",
+			   delay_time);
+		radius_msg_finish_acct(entry->msg, entry->shared_secret,
+				       entry->shared_secret_len);
+		if (radius->conf->msg_dumps)
+			radius_msg_dump(entry->msg);
+	}
+
 	/* retransmit; remove entry if too many attempts */
 	entry->attempts++;
 	hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS,
@@ -624,39 +695,6 @@
 }
 
 
-static void radius_client_list_del(struct radius_client_data *radius,
-				   RadiusType msg_type, const u8 *addr)
-{
-	struct radius_msg_list *entry, *prev, *tmp;
-
-	if (addr == NULL)
-		return;
-
-	entry = radius->msgs;
-	prev = NULL;
-	while (entry) {
-		if (entry->msg_type == msg_type &&
-		    os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
-			if (prev)
-				prev->next = entry->next;
-			else
-				radius->msgs = entry->next;
-			tmp = entry;
-			entry = entry->next;
-			hostapd_logger(radius->ctx, addr,
-				       HOSTAPD_MODULE_RADIUS,
-				       HOSTAPD_LEVEL_DEBUG,
-				       "Removing matching RADIUS message");
-			radius_client_msg_free(tmp);
-			radius->num_msgs--;
-			continue;
-		}
-		prev = entry;
-		entry = entry->next;
-	}
-}
-
-
 /**
  * radius_client_send - Send a RADIUS request
  * @radius: RADIUS client context from radius_client_init()
@@ -668,16 +706,19 @@
  * This function is used to transmit a RADIUS authentication (RADIUS_AUTH) or
  * accounting request (RADIUS_ACCT or RADIUS_ACCT_INTERIM). The only difference
  * between accounting and interim accounting messages is that the interim
- * message will override any pending interim accounting updates while a new
- * accounting message does not remove any pending messages.
+ * message will not be retransmitted. Instead, a callback is used to indicate
+ * that the transmission failed for the specific station @addr so that a new
+ * interim accounting update message can be generated with up-to-date session
+ * data instead of trying to resend old information.
  *
  * The message is added on the retransmission queue and will be retransmitted
  * automatically until a response is received or maximum number of retries
- * (RADIUS_CLIENT_MAX_RETRIES) is reached.
+ * (RADIUS_CLIENT_MAX_RETRIES) is reached. No such retries are used with
+ * RADIUS_ACCT_INTERIM, i.e., such a pending message is removed from the queue
+ * automatically on transmission failure.
  *
  * The related device MAC address can be used to identify pending messages that
- * can be removed with radius_client_flush_auth() or with interim accounting
- * updates.
+ * can be removed with radius_client_flush_auth().
  */
 int radius_client_send(struct radius_client_data *radius,
 		       struct radius_msg *msg, RadiusType msg_type,
@@ -690,11 +731,6 @@
 	int s, res;
 	struct wpabuf *buf;
 
-	if (msg_type == RADIUS_ACCT_INTERIM) {
-		/* Remove any pending interim acct update for the same STA. */
-		radius_client_list_del(radius, msg_type, addr);
-	}
-
 	if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
 		if (conf->acct_server && radius->acct_sock < 0)
 			radius_client_init_acct(radius);