Browse Source

qcacmn: Adjust min zero compression to 1

The IPv6 address format allows compression of _one_ or more zero hextets
using "::". However, the current implementation accepts _zero_ or more
zero hextets as valid. Adjust the minimum required hextets for a zero
compression to 1 from 0.

Change-Id: Ibdf406b04bbdc44d4a28fafa6179c104285c915c
CRs-Fixed: 2362739
Dustin Brown 6 years ago
parent
commit
243d00af0b
2 changed files with 43 additions and 11 deletions
  1. 41 11
      qdf/src/qdf_types.c
  2. 2 0
      qdf/test/qdf_types_test.c

+ 41 - 11
qdf/src/qdf_types.c

@@ -498,6 +498,40 @@ QDF_STATUS qdf_ipv4_parse(const char *ipv4_str, struct qdf_ipv4_addr *out_addr)
 }
 qdf_export_symbol(qdf_ipv4_parse);
 
+static inline void qdf_ipv6_apply_zero_comp(struct qdf_ipv6_addr *addr,
+					    uint8_t hextets,
+					    uint8_t zero_comp_index)
+{
+	/* Given the following hypothetical ipv6 address:
+	 * |---------------------------------------|
+	 * | 01 | ab | cd | ef |    |    |    |    |
+	 * |---------------------------------------|
+	 *           ^--- zero_comp_index (2)
+	 * from -----^
+	 * to ---------------------------^
+	 * |    hextets (4)    |
+	 *                     |   zero comp size  |
+	 *           | to move |
+	 *
+	 * We need to apply the zero compression such that we get:
+	 * |---------------------------------------|
+	 * | 01 | ab | 00 | 00 | 00 | 00 | cd | ef |
+	 * |---------------------------------------|
+	 *           |     zero comp     |
+	 *                               |  moved  |
+	 */
+
+	size_t zero_comp_size = (QDF_IPV6_ADDR_HEXTET_COUNT - hextets) * 2;
+	size_t bytes_to_move = (hextets - zero_comp_index) * 2;
+	uint8_t *from = &addr->bytes[zero_comp_index * 2];
+	uint8_t *to = from + zero_comp_size;
+
+	if (bytes_to_move)
+		qdf_mem_move(to, from, bytes_to_move);
+
+	qdf_mem_zero(from, to - from);
+}
+
 QDF_STATUS qdf_ipv6_parse(const char *ipv6_str, struct qdf_ipv6_addr *out_addr)
 {
 	QDF_STATUS status;
@@ -558,22 +592,18 @@ QDF_STATUS qdf_ipv6_parse(const char *ipv6_str, struct qdf_ipv6_addr *out_addr)
 		}
 	}
 
-	/* we must have max hextets or a zero compression */
-	if (hextets_found < QDF_IPV6_ADDR_HEXTET_COUNT && zero_comp == -1)
-		return QDF_STATUS_E_FAILURE;
-
 	ipv6_str = qdf_str_left_trim(ipv6_str);
 	if (ipv6_str[0] != '\0')
 		return QDF_STATUS_E_FAILURE;
 
-	/* shift lower hextets if zero compressed */
-	if (zero_comp >= 0) {
-		uint8_t shift = QDF_IPV6_ADDR_HEXTET_COUNT - hextets_found;
-		void *to = &addr.bytes[(zero_comp + shift) * 2];
-		void *from = &addr.bytes[zero_comp * 2];
+	/* we must have max hextets or a zero compression, but not both */
+	if (hextets_found < QDF_IPV6_ADDR_HEXTET_COUNT) {
+		if (zero_comp < 0)
+			return QDF_STATUS_E_FAILURE;
 
-		qdf_mem_move(to, from, (hextets_found - zero_comp) * 2);
-		qdf_mem_set(from, shift * 2, 0);
+		qdf_ipv6_apply_zero_comp(&addr, hextets_found, zero_comp);
+	} else if (zero_comp > -1) {
+		return QDF_STATUS_E_FAILURE;
 	}
 
 	*out_addr = addr;

+ 2 - 0
qdf/test/qdf_types_test.c

@@ -467,6 +467,8 @@ static uint32_t qdf_types_ut_ipv6_parse(void)
 			       addr_00000000000000000000000000000001);
 	errors += ut_ipv6_pass("0123:4567:89ab:cdef:ABCD:EF01:2345:6789",
 			       addr_0123456789abcdefabcdef0123456789);
+	errors += ut_ipv6_fail("::0123:4567:89ab:cdef:ABCD:EF01:2345:6789");
+	errors += ut_ipv6_fail("0123:4567:89ab:cdef:ABCD:EF01:2345:6789::");
 	errors += ut_ipv6_pass("2001:0db8:85a3:0000:0000:8a2e:0370:7334",
 			       addr_20010db885a3000000008a2e03707334);
 	errors += ut_ipv6_pass("2001:db8:85a3:0:0:8a2e:370:7334",