ie: add parser/builder for hotspot indication element

The parser fully parses the IE and returns the version, Domain ID,
and PPS MO ID. This is meant to be used with an IE in scan results.

The builder only takes the version number, and assumes DGAF disabled,
and no Domain ID or PPS MO ID.
This commit is contained in:
James Prestwood 2019-07-24 11:36:56 -07:00 committed by Denis Kenzior
parent 34800bfa63
commit 6088c06507
2 changed files with 99 additions and 1 deletions

View File

@ -1287,7 +1287,7 @@ bool is_ie_wfa_ie(const uint8_t *data, uint8_t len, uint8_t oi_type)
if (oi_type == IE_WFA_OI_OSEN && len < 22)
return false;
else if (oi_type == IE_WFA_OI_HS20_INDICATION && len < 5)
else if (oi_type == IE_WFA_OI_HS20_INDICATION && len != 5 && len != 7)
return false;
else if (len < 4) /* OI not handled, but at least check length */
return false;
@ -2483,3 +2483,94 @@ int ie_build_roaming_consortium(const uint8_t *rc, size_t rc_len, uint8_t *to)
return 0;
}
int ie_parse_hs20_indication(struct ie_tlv_iter *iter, uint8_t *version_out,
uint16_t *pps_mo_id_out, uint8_t *domain_id_out)
{
unsigned int len = ie_tlv_iter_get_length(iter);
const uint8_t *data = ie_tlv_iter_get_data(iter);
uint8_t hs20_config;
bool pps_mo_present, domain_id_present;
if (!is_ie_wfa_ie(data, iter->len, IE_WFA_OI_HS20_INDICATION))
return -EPROTOTYPE;
hs20_config = l_get_u8(data + 4);
pps_mo_present = util_is_bit_set(hs20_config, 1);
domain_id_present = util_is_bit_set(hs20_config, 2);
/*
* Hotspot 2.0 Spec - Section 3.1.1
*
* "Either the PPS MO ID field or the ANQP Domain ID field (these
* are mutually exclusive fields) is included in the HS2.0 Indication
* element"
*/
if (pps_mo_present && domain_id_present)
return -EPROTOTYPE;
if (version_out)
*version_out = util_bit_field(hs20_config, 4, 4);
if (pps_mo_id_out)
*pps_mo_id_out = 0;
if (domain_id_out)
*domain_id_out = 0;
/* No PPS MO ID or Domain ID */
if (len == 5)
return 0;
/* we know from is_ie_wfa_ie that the length must be 7 */
if (pps_mo_present) {
if (pps_mo_id_out)
*pps_mo_id_out = l_get_u16(data + 5);
} else if (domain_id_present) {
if (domain_id_out)
*domain_id_out = l_get_u16(data + 5);
}
return 0;
}
int ie_parse_hs20_indication_from_data(const uint8_t *data, size_t len,
uint8_t *version, uint16_t *pps_mo_id,
uint8_t *domain_id)
{
struct ie_tlv_iter iter;
ie_tlv_iter_init(&iter, data, len);
if (!ie_tlv_iter_next(&iter))
return -EMSGSIZE;
if (ie_tlv_iter_get_tag(&iter) != IE_TYPE_VENDOR_SPECIFIC)
return -EPROTOTYPE;
return ie_parse_hs20_indication(&iter, version, pps_mo_id, domain_id);
}
/*
* Only use version for building as this is meant for the (Re)Association IE.
* In this case DGAF is always disabled, Domain ID should not be present, and
* this device was not configured with PerProviderSubscription MO.
*/
int ie_build_hs20_indication(uint8_t version, uint8_t *to)
{
if (version > 2)
return -EINVAL;
*to++ = IE_TYPE_VENDOR_SPECIFIC;
*to++ = 5;
memcpy(to, wifi_alliance_oui, 3);
to += 3;
*to++ = IE_WFA_OI_HS20_INDICATION;
*to++ = (version << 4) & 0xf0;
return 0;
}

View File

@ -517,3 +517,10 @@ int ie_parse_roaming_consortium_from_data(const uint8_t *data, size_t len,
size_t *oi3_len_out);
int ie_build_roaming_consortium(const uint8_t *rc, size_t rc_len, uint8_t *to);
int ie_parse_hs20_indication(struct ie_tlv_iter *iter, uint8_t *version,
uint16_t *pps_mo_id, uint8_t *domain_id);
int ie_parse_hs20_indication_from_data(const uint8_t *data, size_t len,
uint8_t *version, uint16_t *pps_mo_id,
uint8_t *domain_id);
int ie_build_hs20_indication(uint8_t version, uint8_t *to);