Cumulative patch from commit 897a5ccee83090b837aad63b81dbc4d0e77d06f5

897a5cc WNM: Remove unnecessary present flag
f6ce70d WNM: Fix neighbor report subelement formats
e9cb7b9 WNM: Fix neighbor report subelement parser to not leak memory
1aa6f95 WNM: Fix neighbor report subelement parser
5583b8d Document and rename HT Capability/Operation fields
1dde5b5 Remove PSMP option from ht_capab

Change-Id: I0a0a00d2c411f57830098430e59c2a758ab87d7f
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 1ca4c71..e395ef1 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -334,10 +334,10 @@
 			wpa_printf(MSG_DEBUG, "WNM: Too short TSF");
 			break;
 		}
+		os_free(rep->tsf_info);
 		rep->tsf_info = os_zalloc(sizeof(struct tsf_info));
 		if (rep->tsf_info == NULL)
 			break;
-		rep->tsf_info->present = 1;
 		os_memcpy(rep->tsf_info->tsf_offset, pos, 2);
 		os_memcpy(rep->tsf_info->beacon_interval, pos + 2, 2);
 		break;
@@ -347,11 +347,11 @@
 				   "country string");
 			break;
 		}
+		os_free(rep->con_coun_str);
 		rep->con_coun_str =
 			os_zalloc(sizeof(struct condensed_country_string));
 		if (rep->con_coun_str == NULL)
 			break;
-		rep->con_coun_str->present = 1;
 		os_memcpy(rep->con_coun_str->country_string, pos, 2);
 		break;
 	case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE:
@@ -360,25 +360,25 @@
 				   "candidate");
 			break;
 		}
+		os_free(rep->bss_tran_can);
 		rep->bss_tran_can =
 			os_zalloc(sizeof(struct bss_transition_candidate));
 		if (rep->bss_tran_can == NULL)
 			break;
-		rep->bss_tran_can->present = 1;
 		rep->bss_tran_can->preference = pos[0];
 		break;
 	case WNM_NEIGHBOR_BSS_TERMINATION_DURATION:
-		if (elen < 12) {
+		if (elen < 10) {
 			wpa_printf(MSG_DEBUG, "WNM: Too short BSS termination "
 				   "duration");
 			break;
 		}
+		os_free(rep->bss_term_dur);
 		rep->bss_term_dur =
 			os_zalloc(sizeof(struct bss_termination_duration));
 		if (rep->bss_term_dur == NULL)
 			break;
-		rep->bss_term_dur->present = 1;
-		os_memcpy(rep->bss_term_dur->duration, pos, 12);
+		os_memcpy(rep->bss_term_dur->duration, pos, 10);
 		break;
 	case WNM_NEIGHBOR_BEARING:
 		if (elen < 8) {
@@ -386,51 +386,51 @@
 				   "bearing");
 			break;
 		}
+		os_free(rep->bearing);
 		rep->bearing = os_zalloc(sizeof(struct bearing));
 		if (rep->bearing == NULL)
 			break;
-		rep->bearing->present = 1;
 		os_memcpy(rep->bearing->bearing, pos, 8);
 		break;
 	case WNM_NEIGHBOR_MEASUREMENT_PILOT:
-		if (elen < 2) {
+		if (elen < 1) {
 			wpa_printf(MSG_DEBUG, "WNM: Too short measurement "
 				   "pilot");
 			break;
 		}
+		os_free(rep->meas_pilot);
 		rep->meas_pilot = os_zalloc(sizeof(struct measurement_pilot));
 		if (rep->meas_pilot == NULL)
 			break;
-		rep->meas_pilot->present = 1;
 		rep->meas_pilot->measurement_pilot = pos[0];
-		rep->meas_pilot->num_vendor_specific = pos[1];
-		os_memcpy(rep->meas_pilot->vendor_specific, pos + 2, elen - 2);
+		rep->meas_pilot->subelem_len = elen - 1;
+		os_memcpy(rep->meas_pilot->subelems, pos + 1, elen - 1);
 		break;
 	case WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES:
-		if (elen < 4) {
+		if (elen < 5) {
 			wpa_printf(MSG_DEBUG, "WNM: Too short RRM enabled "
 				   "capabilities");
 			break;
 		}
+		os_free(rep->rrm_cap);
 		rep->rrm_cap =
 			os_zalloc(sizeof(struct rrm_enabled_capabilities));
 		if (rep->rrm_cap == NULL)
 			break;
-		rep->rrm_cap->present = 1;
-		os_memcpy(rep->rrm_cap->capabilities, pos, 4);
+		os_memcpy(rep->rrm_cap->capabilities, pos, 5);
 		break;
 	case WNM_NEIGHBOR_MULTIPLE_BSSID:
-		if (elen < 2) {
+		if (elen < 1) {
 			wpa_printf(MSG_DEBUG, "WNM: Too short multiple BSSID");
 			break;
 		}
+		os_free(rep->mul_bssid);
 		rep->mul_bssid = os_zalloc(sizeof(struct multiple_bssid));
 		if (rep->mul_bssid == NULL)
 			break;
-		rep->mul_bssid->present = 1;
 		rep->mul_bssid->max_bssid_indicator = pos[0];
-		rep->mul_bssid->num_vendor_specific = pos[1];
-		os_memcpy(rep->mul_bssid->vendor_specific, pos + 2, elen - 2);
+		rep->mul_bssid->subelem_len = elen - 1;
+		os_memcpy(rep->mul_bssid->subelems, pos + 1, elen - 1);
 		break;
 	}
 }
@@ -461,8 +461,15 @@
 
 		id = *pos++;
 		elen = *pos++;
+		wpa_printf(MSG_DEBUG, "WNM: Subelement id=%u len=%u", id, elen);
+		left -= 2;
+		if (elen > left) {
+			wpa_printf(MSG_DEBUG,
+				   "WNM: Truncated neighbor report subelement");
+			break;
+		}
 		wnm_parse_neighbor_report_elem(rep, id, elen, pos);
-		left -= 2 + elen;
+		left -= elen;
 		pos += elen;
 	}
 }
@@ -695,10 +702,12 @@
 				wpa_printf(MSG_DEBUG, "WNM: Truncated request");
 				return;
 			}
-			wnm_parse_neighbor_report(
-				wpa_s, pos, len,
-				&wpa_s->wnm_neighbor_report_elements[
-					wpa_s->wnm_num_neighbor_report]);
+			if (tag == WLAN_EID_NEIGHBOR_REPORT) {
+				struct neighbor_report *rep;
+				rep = &wpa_s->wnm_neighbor_report_elements[
+					wpa_s->wnm_num_neighbor_report];
+				wnm_parse_neighbor_report(wpa_s, pos, len, rep);
+			}
 
 			pos += len;
 			wpa_s->wnm_num_neighbor_report++;