Commit cf139196 authored by Alex Elder's avatar Alex Elder Committed by Paolo Abeni

net: ipa: validate IPA table memory earlier

Add checks in ipa_table_init() to ensure the memory regions defined
for IPA filter and routing tables are valid.

For routing tables, the checks ensure:
  - The non-hashed IPv4 and IPv6 routing tables are defined
  - The non-hashed IPv4 and IPv6 routing tables are the same size
  - The number entries in the non-hashed IPv4 routing table is enough
    to hold the number entries available to the modem, plus at least
    one usable by the AP.

For filter tables, the checks ensure:
  - The non-hashed IPv4 and IPv6 filter tables are defined
  - The non-hashed IPv4 and IPv6 filter tables are the same size
  - The number entries in the non-hashed IPv4 filter table is enough
    to hold the endpoint bitmap, plus an entry for each defined
    endpoint that supports filtering.

In addition, for both routing and filter tables:
  - If hashing isn't supported (IPA v4.2), hashed tables are zero size
  - If hashing *is* supported, all hashed tables are the same size as
    their non-hashed counterparts.

When validating the size of routing tables, require the AP to have
at least one entry (in addition to those used by the modem).
Signed-off-by: default avatarAlex Elder <elder@linaro.org>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 2554322b
......@@ -134,9 +134,25 @@ static void ipa_table_validate_build(void)
BUILD_BUG_ON(IPA_ROUTE_COUNT_MAX > 32);
/* The modem must be allotted at least one route table entry */
BUILD_BUG_ON(!IPA_ROUTE_MODEM_COUNT);
/* But it can't have more than what is available */
BUILD_BUG_ON(IPA_ROUTE_MODEM_COUNT > IPA_ROUTE_COUNT_MAX);
/* AP must too, but we can't use more than what is available */
BUILD_BUG_ON(IPA_ROUTE_MODEM_COUNT >= IPA_ROUTE_COUNT_MAX);
}
static const struct ipa_mem *
ipa_table_mem(struct ipa *ipa, bool filter, bool hashed, bool ipv6)
{
enum ipa_mem_id mem_id;
mem_id = filter ? hashed ? ipv6 ? IPA_MEM_V6_FILTER_HASHED
: IPA_MEM_V4_FILTER_HASHED
: ipv6 ? IPA_MEM_V6_FILTER
: IPA_MEM_V4_FILTER
: hashed ? ipv6 ? IPA_MEM_V6_ROUTE_HASHED
: IPA_MEM_V4_ROUTE_HASHED
: ipv6 ? IPA_MEM_V6_ROUTE
: IPA_MEM_V4_ROUTE;
return ipa_mem_find(ipa, mem_id);
}
static bool
......@@ -604,8 +620,77 @@ void ipa_table_config(struct ipa *ipa)
ipa_route_config(ipa, true);
}
/*
* Initialize a coherent DMA allocation containing initialized filter and
/* Zero modem_route_count means filter table memory check */
static bool ipa_table_mem_valid(struct ipa *ipa, bool modem_route_count)
{
bool hash_support = ipa_table_hash_support(ipa);
bool filter = !modem_route_count;
const struct ipa_mem *mem_hashed;
const struct ipa_mem *mem_ipv4;
const struct ipa_mem *mem_ipv6;
u32 count;
/* IPv4 and IPv6 non-hashed tables are expected to be defined and
* have the same size. Both must have at least two entries (and
* would normally have more than that).
*/
mem_ipv4 = ipa_table_mem(ipa, filter, false, false);
if (!mem_ipv4)
return false;
mem_ipv6 = ipa_table_mem(ipa, filter, false, true);
if (!mem_ipv6)
return false;
if (mem_ipv4->size != mem_ipv6->size)
return false;
/* Make sure the regions are big enough */
count = mem_ipv4->size / sizeof(__le64);
if (count < 2)
return false;
if (filter) {
/* Filter tables must able to hold the endpoint bitmap plus
* an entry for each endpoint that supports filtering
*/
if (count < 1 + hweight32(ipa->filter_map))
return false;
} else {
/* Routing tables must be able to hold all modem entries,
* plus at least one entry for the AP.
*/
if (count < modem_route_count + 1)
return false;
}
/* If hashing is supported, hashed tables are expected to be defined,
* and have the same size as non-hashed tables. If hashing is not
* supported, hashed tables are expected to have zero size (or not
* be defined).
*/
mem_hashed = ipa_table_mem(ipa, filter, true, false);
if (hash_support) {
if (!mem_hashed || mem_hashed->size != mem_ipv4->size)
return false;
} else {
if (mem_hashed && mem_hashed->size)
return false;
}
/* Same check for IPv6 tables */
mem_hashed = ipa_table_mem(ipa, filter, true, true);
if (hash_support) {
if (!mem_hashed || mem_hashed->size != mem_ipv6->size)
return false;
} else {
if (mem_hashed && mem_hashed->size)
return false;
}
return true;
}
/* Initialize a coherent DMA allocation containing initialized filter and
* route table data. This is used when initializing or resetting the IPA
* filter or route table.
*
......@@ -653,6 +738,11 @@ int ipa_table_init(struct ipa *ipa)
ipa_table_validate_build();
if (!ipa_table_mem_valid(ipa, 0))
return -EINVAL;
if (!ipa_table_mem_valid(ipa, IPA_ROUTE_MODEM_COUNT))
return -EINVAL;
/* The IPA hardware requires route and filter table rules to be
* aligned on a 128-byte boundary. We put the "zero rule" at the
* base of the table area allocated here. The DMA address returned
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment