/* decode home realm query */ int bcm_decode_hspot_anqp_nai_home_realm_query(bcm_decode_t *pkt, bcm_decode_hspot_anqp_nai_home_realm_query_t *realm) { int i; WL_PRPKT("packet for hotspot NAI home realm decoding", bcm_decode_current_ptr(pkt), bcm_decode_remaining(pkt)); memset(realm, 0, sizeof(*realm)); if (bcm_decode_is_zero_length(pkt)) return TRUE; if (!bcm_decode_byte(pkt, &realm->count)) { WL_ERROR(("decode error\n")); return FALSE; } if (realm->count > BCM_DECODE_HSPOT_ANQP_MAX_HOME_REALM) { WL_ERROR(("home realm count %d > %d\n", realm->count, BCM_DECODE_HSPOT_ANQP_MAX_HOME_REALM)); return FALSE; } for (i = 0; i < realm->count; i++) { if (!pktDecodeHspotAnqpNaiHomeRealmQueryData(pkt, &realm->data[i])) { return FALSE; } } realm->isDecodeValid = TRUE; return TRUE; }
/* decode operating class indication */ int bcm_decode_hspot_anqp_operating_class_indication(bcm_decode_t *pkt, bcm_decode_hspot_anqp_operating_class_indication_t *opClassList) { int count; WL_PRPKT("packet for hotspot operating class indication decoding", bcm_decode_current_ptr(pkt), bcm_decode_remaining(pkt)); memset(opClassList, 0, sizeof(*opClassList)); if (bcm_decode_is_zero_length(pkt)) return TRUE; count = bcm_decode_remaining(pkt); if (count > BCM_DECODE_HSPOT_ANQP_MAX_OPCLASS_LIST_SIZE) { WL_ERROR(("operating class indication list size is too large %d\n", BCM_DECODE_HSPOT_ANQP_MAX_OPCLASS_LIST_SIZE)); return FALSE; } if (!bcm_decode_bytes(pkt, count, (uint8 *)opClassList->opClass)) { WL_ERROR(("bcm_decode_bytes failed")); return FALSE; } opClassList->opClassLen = count; opClassList->isDecodeValid = TRUE; return TRUE; }
/* decode capability list */ int bcm_decode_hspot_anqp_capability_list(bcm_decode_t *pkt, bcm_decode_hspot_anqp_capability_list_t *capList) { int count, i; WL_PRPKT("packet for hotspot capability list decoding", bcm_decode_current_ptr(pkt), bcm_decode_remaining(pkt)); memset(capList, 0, sizeof(*capList)); if (bcm_decode_is_zero_length(pkt)) return TRUE; count = bcm_decode_remaining(pkt); for (i = 0; i < count; i++) { if (i >= BCM_DECODE_ANQP_MAX_LIST_SIZE) { WL_ERROR(("truncating capability list to %d\n", BCM_DECODE_ANQP_MAX_LIST_SIZE)); return FALSE; } (void)bcm_decode_byte(pkt, &capList->capId[capList->capLen++]); } capList->isDecodeValid = TRUE; return TRUE; }
/* decode connection capability */ int bcm_decode_hspot_anqp_connection_capability(bcm_decode_t *pkt, bcm_decode_hspot_anqp_connection_capability_t *cap) { WL_PRPKT("packet for hotspot connection capability decoding", bcm_decode_current_ptr(pkt), bcm_decode_remaining(pkt)); memset(cap, 0, sizeof(*cap)); if (bcm_decode_is_zero_length(pkt)) return TRUE; while (bcm_decode_remaining(pkt) > 0 && cap->numConnectCap < BCM_DECODE_HSPOT_ANQP_MAX_CONNECTION_CAPABILITY) { if (!pktDecodeHspotAnqpProtoPortTuple(pkt, &cap->tuple[cap->numConnectCap])) { return FALSE; } else { cap->numConnectCap++; } } cap->isDecodeValid = TRUE; return TRUE; }
/* decode operator friendly name */ int bcm_decode_hspot_anqp_operator_friendly_name(bcm_decode_t *pkt, bcm_decode_hspot_anqp_operator_friendly_name_t *op) { WL_PRPKT("packet for hotspot operator friendly name decoding", bcm_decode_current_ptr(pkt), bcm_decode_remaining(pkt)); memset(op, 0, sizeof(*op)); if (bcm_decode_is_zero_length(pkt)) return TRUE; while (bcm_decode_remaining(pkt) > 0 && op->numName < BCM_DECODE_HSPOT_ANQP_MAX_OPERATOR_NAME) { if (!pktDecodeHspotAnqpOperatorNameDuple(pkt, &op->duple[op->numName])) { return FALSE; } else { op->numName++; } } op->isDecodeValid = TRUE; return TRUE; }
/* decode icon request */ int bcm_decode_hspot_anqp_icon_request(bcm_decode_t *pkt, bcm_decode_hspot_anqp_icon_request_t *request) { WL_PRPKT("packet for hotspot icon request decoding", bcm_decode_current_ptr(pkt), bcm_decode_remaining(pkt)); memset(request, 0, sizeof(*request)); if (bcm_decode_is_zero_length(pkt)) return TRUE; request->filenameLength = bcm_decode_remaining(pkt); if (request->filenameLength > BCM_DECODE_HSPOT_ANQP_MAX_ICON_FILENAME_LENGTH) { WL_ERROR(("icon filename exceeds buffer %d > %d\n", request->filenameLength, BCM_DECODE_HSPOT_ANQP_MAX_ICON_FILENAME_LENGTH)); return FALSE; } if (!bcm_decode_bytes(pkt, request->filenameLength, (uint8 *)request->filename)) { WL_ERROR(("bcm_decode_bytes failed")); return FALSE; } request->filename[request->filenameLength] = 0; request->isDecodeValid = TRUE; return TRUE; }
static void testEncode(void) { uint8 adBuffer[BUFFER_SIZE]; pktEncodeT ad; TEST(pktEncodeInit(&enc, sizeof(buffer), buffer), "pktEncodeInit failed"); TEST(pktEncodeIeHotspotIndication2(&enc, TRUE, TRUE, HSPOT_RELEASE_2), "pktEncodeIeHotspotIndication2 failed"); TEST(pktEncodeIeInterworking(&enc, IW_ANT_WILDCARD_NETWORK, FALSE, FALSE, FALSE, FALSE, TRUE, 0, 0, (struct ether_addr *)"\xff\xff\xff\xff\xff\xff"), "pktEncodeIeInterworking failed"); TEST(pktEncodeInit(&ad, sizeof(adBuffer), adBuffer), "pktEncodeInit failed"); TEST(pktEncodeIeAdvertisementProtocolTuple(&ad, ADVP_PAME_BI_DEPENDENT, 0xff, ADVP_ANQP_PROTOCOL_ID), "pktEncodeIeAdvertisementProtocolTuple failed"); TEST(pktEncodeIeAdvertiseProtocol(&enc, pktEncodeLength(&ad), pktEncodeBuf(&ad)), "pktEncodeIeAdvertiseProtocol failed"); TEST(pktEncodeIeRoamingConsortium(&enc, 0xff, 3, (uint8 *)"\x00\x11\x22", 4, (uint8 *)"\x55\x66\x77\x88", 4, (uint8 *)"\xaa\xbb\xcc\xdd"), "pktEncodeIeRoamingConsortium failed"); TEST(pktEncodeIeExtendedCapabilities(&enc, 0x80000000), "pktEncodeIeExtendedCapabilities failed"); WL_PRPKT("encoded IEs", pktEncodeBuf(&enc), pktEncodeLength(&enc)); }
/* decode WAN metrics */ int bcm_decode_hspot_anqp_wan_metrics(bcm_decode_t *pkt, bcm_decode_hspot_anqp_wan_metrics_t *wanMetrics) { uint8 wanInfo; WL_PRPKT("packet for hotspot WAN metrics decoding", bcm_decode_current_ptr(pkt), bcm_decode_remaining(pkt)); memset(wanMetrics, 0, sizeof(*wanMetrics)); if (bcm_decode_is_zero_length(pkt)) return TRUE; if (!bcm_decode_byte(pkt, &wanInfo)) { WL_ERROR(("decode error\n")); return FALSE; } wanMetrics->linkStatus = (wanInfo & HSPOT_WAN_LINK_STATUS_MASK) >> HSPOT_WAN_LINK_STATUS_SHIFT; wanMetrics->symmetricLink = (wanInfo & HSPOT_WAN_SYMMETRIC_LINK_MASK) >> HSPOT_WAN_SYMMETRIC_LINK_SHIFT; wanMetrics->atCapacity = (wanInfo & HSPOT_WAN_AT_CAPACITY_MASK) >> HSPOT_WAN_AT_CAPACITY_SHIFT; if (!bcm_decode_le32(pkt, &wanMetrics->dlinkSpeed)) { WL_ERROR(("decode error\n")); return FALSE; } if (!bcm_decode_le32(pkt, &wanMetrics->ulinkSpeed)) { WL_ERROR(("decode error\n")); return FALSE; } if (!bcm_decode_byte(pkt, &wanMetrics->dlinkLoad)) { WL_ERROR(("decode error\n")); return FALSE; } if (!bcm_decode_byte(pkt, &wanMetrics->ulinkLoad)) { WL_ERROR(("decode error\n")); return FALSE; } if (!bcm_decode_le16(pkt, &wanMetrics->lmd)) { WL_ERROR(("decode error\n")); return FALSE; } wanMetrics->dlinkAvailable = wanMetrics->dlinkSpeed - wanMetrics->dlinkSpeed * wanMetrics->dlinkLoad / 255; wanMetrics->ulinkAvailable = wanMetrics->ulinkSpeed - wanMetrics->ulinkSpeed * wanMetrics->ulinkLoad / 255; wanMetrics->isDecodeValid = TRUE; return TRUE; }
/* decode icon binary file */ int bcm_decode_hspot_anqp_icon_binary_file(bcm_decode_t *pkt, bcm_decode_hspot_anqp_icon_binary_file_t *icon) { WL_PRPKT("packet for hotspot icon binary file decoding", bcm_decode_current_ptr(pkt), bcm_decode_remaining(pkt)); memset(icon, 0, sizeof(*icon)); if (bcm_decode_is_zero_length(pkt)) return TRUE; if (!bcm_decode_byte(pkt, &icon->status)) { WL_ERROR(("decode error\n")); return FALSE; } if (!bcm_decode_byte(pkt, &icon->typeLength)) { WL_ERROR(("decode error\n")); return FALSE; } if (icon->typeLength > bcm_decode_remaining(pkt)) { WL_ERROR(("icon type length exceeds packet %d > %d\n", icon->typeLength, bcm_decode_remaining(pkt))); return FALSE; } if (icon->typeLength > BCM_DECODE_HSPOT_ANQP_MAX_ICON_TYPE_LENGTH) { WL_ERROR(("icon type exceeds buffer %d > %d\n", icon->typeLength, BCM_DECODE_HSPOT_ANQP_MAX_ICON_TYPE_LENGTH)); return FALSE; } if (icon->typeLength > 0 && !bcm_decode_bytes(pkt, icon->typeLength, (uint8 *)icon->type)) { WL_ERROR(("bcm_decode_bytes failed")); return FALSE; } icon->type[icon->typeLength] = 0; if (!bcm_decode_le16(pkt, &icon->binaryLength)) { WL_ERROR(("decode error\n")); return FALSE; } if (icon->binaryLength > bcm_decode_remaining(pkt)) { WL_ERROR(("icon binary length exceeds packet %d > %d\n", icon->binaryLength, bcm_decode_remaining(pkt))); return FALSE; } if (icon->binaryLength > 0 && !bcm_decode_bytes(pkt, icon->binaryLength, (uint8 *)icon->binary)) { WL_ERROR(("bcm_decode_bytes failed")); return FALSE; } icon->isDecodeValid = TRUE; return TRUE; }
static void testDecodeCorruptLength(void) { pktDecodeT dec; pktIeT ie; uint8 *lenPtr; uint8 save; TEST(pktDecodeInit(&dec, pktEncodeLength(&enc), pktEncodeBuf(&enc)), "pktDecodeInit failed"); WL_PRPKT("decode packet", pktDecodeBuf(&dec), pktDecodeBufLength(&dec)); lenPtr = &pktDecodeBuf(&dec)[1]; save = *lenPtr; *lenPtr += 1; TEST(pktDecodeIe(&dec, &ie) == 1, "pktDecodeIe failed"); *lenPtr = 0xff; TEST(pktDecodeIe(&dec, &ie) == 0, "pktDecodeIe failed"); *lenPtr = save; }
/* decode anonymous NAI */ int bcm_decode_hspot_anqp_anonymous_nai(bcm_decode_t *pkt, bcm_decode_hspot_anqp_anonymous_nai_t *anonymous) { WL_PRPKT("packet for hotspot anonymous NAI decoding", bcm_decode_current_ptr(pkt), bcm_decode_remaining(pkt)); memset(anonymous, 0, sizeof(*anonymous)); if (bcm_decode_is_zero_length(pkt)) return TRUE; if (!bcm_decode_le16(pkt, &anonymous->naiLen)) { WL_ERROR(("decode error\n")); return FALSE; } if (anonymous->naiLen > bcm_decode_remaining(pkt)) { WL_ERROR(("anonymous NAI length exceeds packet %d > %d\n", anonymous->naiLen, bcm_decode_remaining(pkt))); return FALSE; } if (anonymous->naiLen > BCM_DECODE_HSPOT_ANQP_MAX_NAI_SIZE) { WL_ERROR(("anonymous NAI exceeds buffer %d > %d\n", anonymous->naiLen, BCM_DECODE_HSPOT_ANQP_MAX_NAI_SIZE)); return FALSE; } if (!bcm_decode_bytes(pkt, anonymous->naiLen, (uint8 *)anonymous->nai)) { WL_ERROR(("bcm_decode_bytes failed")); return FALSE; } anonymous->nai[anonymous->naiLen] = 0; anonymous->isDecodeValid = TRUE; return TRUE; }
/* decode WNM-notification request for deauthentication imminent */ int bcm_decode_wnm_deauthentication_imminent(bcm_decode_t *pkt, bcm_decode_wnm_deauthentication_imminent_t *wnm) { uint8 byte, len; uint8 oui[WFA_OUI_LEN]; WL_PRPKT("packet for WNM deauthentication imminent decoding", bcm_decode_buf(pkt), bcm_decode_buf_length(pkt)); memset(wnm, 0, sizeof(*wnm)); if (!bcm_decode_byte(pkt, &byte) || byte != DOT11_ACTION_CAT_WNM) { WL_ERROR(("WNM action category\n")); return FALSE; } if (!bcm_decode_byte(pkt, &byte) || byte != DOT11_WNM_ACTION_NOTFCTN_REQ) { WL_ERROR(("WNM notifcation request\n")); return FALSE; } if (!bcm_decode_byte(pkt, &wnm->dialogToken)) { WL_ERROR(("dialog token\n")); return FALSE; } if (!bcm_decode_byte(pkt, &byte) || byte != HSPOT_WNM_TYPE) { WL_ERROR(("WNM type\n")); return FALSE; } if (!bcm_decode_byte(pkt, &byte) || byte != DOT11_MNG_VS_ID) { WL_ERROR(("vendor specific ID\n")); return FALSE; } if (!bcm_decode_byte(pkt, &len) || len < 8) { WL_ERROR(("length\n")); return FALSE; } if (len > bcm_decode_remaining(pkt)) { WL_ERROR(("length exceeds packet %d > %d\n", len, bcm_decode_remaining(pkt))); return FALSE; } if (!bcm_decode_bytes(pkt, WFA_OUI_LEN, oui) || memcmp(oui, WFA_OUI, WFA_OUI_LEN) != 0) { WL_ERROR(("WFA OUI\n")); return FALSE; } if (!bcm_decode_byte(pkt, &byte) || byte != HSPOT_WNM_DEAUTHENTICATION_IMMINENT) { return FALSE; } if (!bcm_decode_byte(pkt, &wnm->reason)) { WL_ERROR(("deauth reason\n")); return FALSE; } if (!bcm_decode_le16(pkt, &wnm->reauthDelay)) { WL_ERROR(("reauth delay\n")); return FALSE; } if (!bcm_decode_byte(pkt, &wnm->urlLength) || wnm->urlLength > bcm_decode_remaining(pkt)) { WL_ERROR(("URL length\n")); return FALSE; } if (wnm->urlLength > 0) { bcm_decode_bytes(pkt, wnm->urlLength, (uint8 *)wnm->url); } wnm->url[wnm->urlLength] = 0; return TRUE; }
/* decode WNM-notification request for subscription remediation */ int bcm_decode_wnm_subscription_remediation( bcm_decode_t *pkt, bcm_decode_wnm_subscription_remediation_t *wnm) { uint8 byte, len; uint8 oui[WFA_OUI_LEN]; WL_PRPKT("packet for WNM subscription remediation decoding", bcm_decode_buf(pkt), bcm_decode_buf_length(pkt)); memset(wnm, 0, sizeof(*wnm)); if (!bcm_decode_byte(pkt, &byte) || byte != DOT11_ACTION_CAT_WNM) { WL_ERROR(("WNM action category\n")); return FALSE; } if (!bcm_decode_byte(pkt, &byte) || byte != DOT11_WNM_ACTION_NOTFCTN_REQ) { WL_ERROR(("WNM notifcation request\n")); return FALSE; } if (!bcm_decode_byte(pkt, &wnm->dialogToken)) { WL_ERROR(("dialog token\n")); return FALSE; } if (!bcm_decode_byte(pkt, &byte) || byte != HSPOT_WNM_TYPE) { WL_ERROR(("WNM type\n")); return FALSE; } if (!bcm_decode_byte(pkt, &byte) || byte != DOT11_MNG_VS_ID) { WL_ERROR(("vendor specific ID\n")); return FALSE; } if (!bcm_decode_byte(pkt, &len) || len < 6) { WL_ERROR(("length\n")); return FALSE; } if (len > bcm_decode_remaining(pkt)) { WL_ERROR(("length exceeds packet %d > %d\n", len, bcm_decode_remaining(pkt))); return FALSE; } if (!bcm_decode_bytes(pkt, WFA_OUI_LEN, oui) || memcmp(oui, WFA_OUI, WFA_OUI_LEN) != 0) { WL_ERROR(("WFA OUI\n")); return FALSE; } if (!bcm_decode_byte(pkt, &byte) || byte != HSPOT_WNM_SUBSCRIPTION_REMEDIATION) { return FALSE; } if (!bcm_decode_byte(pkt, &wnm->urlLength) || wnm->urlLength > bcm_decode_remaining(pkt)) { WL_ERROR(("URL length\n")); return FALSE; } if (wnm->urlLength > 0) { bcm_decode_bytes(pkt, wnm->urlLength, (uint8 *)wnm->url); } wnm->url[wnm->urlLength] = 0; if (bcm_decode_remaining(pkt) > 0 && bcm_decode_byte(pkt, &wnm->serverMethod)) { } return TRUE; }
static void testDecode(void) { pktDecodeT dec; pktIeT ie; pktDecodeT dec1; pktHotspotIndicationT hotspot; pktInterworkingT interworking; pktAdvertisementProtocolT advertise; pktRoamingConsortiumT roam; uint32 cap; TEST(pktDecodeInit(&dec, pktEncodeLength(&enc), pktEncodeBuf(&enc)), "pktDecodeInit failed"); WL_PRPKT("decode packet", pktDecodeBuf(&dec), pktDecodeBufLength(&dec)); TEST(pktDecodeIe(&dec, &ie) == 5, "pktDecodeIe failed"); TEST(pktDecodeInit(&dec1, ie.hotspotIndicationLength, ie.hotspotIndication), "pktDecodeInit failed"); TEST(pktDecodeIeHotspotIndication2(&dec1, &hotspot), "pktDecodeIeHotspotIndication failed"); TEST(hotspot.isDgafDisabled == TRUE, "invalid data"); TEST(hotspot.isOsuBssid == TRUE, "invalid data"); TEST(hotspot.releaseNumber == HSPOT_RELEASE_2, "invalid data"); TEST(pktDecodeInit(&dec1, ie.interworkingLength, ie.interworking), "pktDecodeInit failed"); TEST(pktDecodeIeInterworking(&dec1, &interworking), "pktDecodeIeInterworking failed"); TEST(interworking.accessNetworkType == IW_ANT_WILDCARD_NETWORK, "invalid data"); TEST(interworking.isInternet == FALSE, "invalid data"); TEST(interworking.isAsra == FALSE, "invalid data"); TEST(interworking.isEsr == FALSE, "invalid data"); TEST(interworking.isUesa == FALSE, "invalid data"); TEST(interworking.isVenue == TRUE, "invalid data"); TEST(interworking.venueGroup == 0, "invalid data"); TEST(interworking.venueType == 0, "invalid data"); TEST(interworking.isHessid == TRUE, "invalid data"); TEST(memcmp(&interworking.hessid, "\xff\xff\xff\xff\xff\xff", sizeof(interworking.hessid)) == 0, "invalid data"); TEST(pktDecodeInit(&dec1, ie.advertisementProtocolLength, ie.advertisementProtocol), "pktDecodeInit failed"); TEST(pktDecodeIeAdvertisementProtocol(&dec1, &advertise), "pktDecodeIeAdvertisementProtocol failed"); TEST(advertise.count == 1, "invalid data"); TEST(advertise.protocol[0].queryResponseLimit == 0x7f, "invalid data"); TEST(advertise.protocol[0].isPamebi == FALSE, "invalid data"); TEST(advertise.protocol[0].protocolId == ADVP_ANQP_PROTOCOL_ID, "invalid data"); TEST(pktDecodeInit(&dec1, ie.roamingConsortiumLength, ie.roamingConsortium), "pktDecodeInit failed"); TEST(pktDecodeIeRoamingConsortium(&dec1, &roam), "pktDecodeRoamingConsortium failed"); TEST(roam.anqpOiCount == 0xff, "invalid data"); TEST(roam.count == 3, "invalid data"); TEST(memcmp(roam.oi[0].data, "\x00\x11\x22", roam.oi[0].length) == 0, "invalid data"); TEST(memcmp(roam.oi[1].data, "\x55\x66\x77\x88", roam.oi[1].length) == 0, "invalid data"); TEST(memcmp(roam.oi[2].data, "\xaa\xbb\xcc\xdd", roam.oi[2].length) == 0, "invalid data"); TEST(pktDecodeInit(&dec1, ie.extendedCapabilityLength, ie.extendedCapability), "pktDecodeInit failed"); TEST(pktDecodeIeExtendedCapabilities(&dec1, &cap), "pktDecodeIeExtendedCapabilities failed"); TEST(cap == 0x80000000, "invalid data"); }
/* decode OSU provider list */ int bcm_decode_hspot_anqp_osu_provider_list(bcm_decode_t *pkt, bcm_decode_hspot_anqp_osu_provider_list_t *list) { int len; int i; WL_PRPKT("packet for hotspot OSU provider list decoding", bcm_decode_current_ptr(pkt), bcm_decode_remaining(pkt)); memset(list, 0, sizeof(*list)); if (bcm_decode_is_zero_length(pkt)) return TRUE; /* decode OSU SSID */ if (!bcm_decode_byte(pkt, &list->osuSsidLength)) { WL_ERROR(("decode error\n")); return FALSE; } len = list->osuSsidLength; if (len > BCM_DECODE_HSPOT_ANQP_MAX_OSU_SSID_LENGTH) { WL_ERROR(("length exceeds maximum %d > %d\n", list->osuSsidLength, BCM_DECODE_HSPOT_ANQP_MAX_OSU_SSID_LENGTH)); return FALSE; } if (list->osuSsidLength > bcm_decode_remaining(pkt)) { WL_ERROR(("length exceeds packet %d > %d\n", list->osuSsidLength, bcm_decode_remaining(pkt))); return FALSE; } if (list->osuSsidLength > 0 && !bcm_decode_bytes(pkt, list->osuSsidLength, list->osuSsid)) { WL_ERROR(("bcm_decode_bytes failed")); return FALSE; } list->osuSsid[list->osuSsidLength] = 0; /* decode number of OSU providers */ if (!bcm_decode_byte(pkt, &list->osuProviderCount)) { WL_ERROR(("decode error\n")); return FALSE; } if (list->osuProviderCount > BCM_DECODE_HSPOT_ANQP_MAX_OSU_PROVIDER) { WL_ERROR(("length exceeds maximum %d > %d\n", list->osuProviderCount, BCM_DECODE_HSPOT_ANQP_MAX_OSU_PROVIDER)); return FALSE; } for (i = 0; i < list->osuProviderCount; i++) { bcm_decode_hspot_anqp_osu_provider_t *osu = &list->osuProvider[i]; uint16 osuLength; uint16 nameLength; int remNameLength; uint16 iconLength; int remIconLength; uint16 descLength; int remDescLength; /* decode OSU provider length */ if (!bcm_decode_le16(pkt, &osuLength)) { WL_ERROR(("decode error\n")); return FALSE; } if (osuLength > bcm_decode_remaining(pkt)) { WL_ERROR(("OSU length exceeds packet %d > %d\n", osuLength, bcm_decode_remaining(pkt))); return FALSE; } /* decode OSU friendly name */ if (!bcm_decode_le16(pkt, &nameLength)) { WL_ERROR(("decode error\n")); return FALSE; } if (nameLength > bcm_decode_remaining(pkt)) { WL_ERROR(("name length exceeds packet %d > %d\n", nameLength, bcm_decode_remaining(pkt))); return FALSE; } remNameLength = nameLength; while (remNameLength > 0 && osu->name.numName < BCM_DECODE_HSPOT_ANQP_MAX_OPERATOR_NAME) { int startOffset = bcm_decode_offset(pkt); if (!pktDecodeHspotAnqpOperatorNameDuple(pkt, &osu->name.duple[osu->name.numName])) { return FALSE; } else { osu->name.numName++; } /* update remaining name length */ remNameLength -= bcm_decode_offset(pkt) - startOffset; } /* decode OSU server URI */ if (!bcm_decode_byte(pkt, &osu->uriLength)) { WL_ERROR(("decode error\n")); return FALSE; } if (osu->uriLength > BCM_DECODE_HSPOT_ANQP_MAX_URI_LENGTH) { WL_ERROR(("URI exceeds buffer %d > %d\n", osu->uriLength, BCM_DECODE_HSPOT_ANQP_MAX_URI_LENGTH)); return FALSE; } if (osu->uriLength > 0 && !bcm_decode_bytes(pkt, osu->uriLength, (uint8 *)osu->uri)) { WL_ERROR(("bcm_decode_bytes failed")); return FALSE; } osu->uri[osu->uriLength] = 0; /* decode OSU method */ if (!bcm_decode_byte(pkt, &osu->methodLength)) { WL_ERROR(("decode error\n")); return FALSE; } if (osu->methodLength > BCM_DECODE_HSPOT_ANQP_MAX_METHOD_LENGTH) { WL_ERROR(("method exceeds buffer %d > %d\n", osu->methodLength, BCM_DECODE_HSPOT_ANQP_MAX_METHOD_LENGTH)); return FALSE; } if (!bcm_decode_bytes(pkt, osu->methodLength, (uint8 *)osu->method)) { WL_ERROR(("bcm_decode_bytes failed\n")); return FALSE; } /* decode icon metadata */ if (!bcm_decode_le16(pkt, &iconLength)) { WL_ERROR(("decode error\n")); return FALSE; } remIconLength = iconLength; while (remIconLength > 0 && osu->iconMetadataCount < BCM_DECODE_HSPOT_ANQP_MAX_ICON_METADATA_LENGTH) { int startOffset = bcm_decode_offset(pkt); if (!pktDecodeHspotAnqpIconMetadata(pkt, &osu->iconMetadata[osu->iconMetadataCount])) { return FALSE; } else { osu->iconMetadataCount++; } /* update remaining name length */ remIconLength -= bcm_decode_offset(pkt) - startOffset; } /* decode OSU NAI */ if (!bcm_decode_byte(pkt, &osu->naiLength)) { WL_ERROR(("decode error\n")); return FALSE; } if (osu->naiLength > BCM_DECODE_HSPOT_ANQP_MAX_NAI_LENGTH) { WL_ERROR(("NAI exceeds buffer %d > %d\n", osu->naiLength, BCM_DECODE_HSPOT_ANQP_MAX_NAI_LENGTH)); return FALSE; } if (osu->naiLength > 0 && !bcm_decode_bytes(pkt, osu->naiLength, (uint8 *)osu->nai)) { WL_ERROR(("bcm_decode_bytes failed")); return FALSE; } osu->nai[osu->naiLength] = 0; /* decode OSU service description */ if (!bcm_decode_le16(pkt, &descLength)) { WL_ERROR(("decode error\n")); return FALSE; } if (descLength > bcm_decode_remaining(pkt)) { WL_ERROR(("name length exceeds packet %d > %d\n", descLength, bcm_decode_remaining(pkt))); return FALSE; } remDescLength = descLength; while (remDescLength > 0 && osu->desc.numName < BCM_DECODE_HSPOT_ANQP_MAX_OPERATOR_NAME) { int startOffset = bcm_decode_offset(pkt); if (!pktDecodeHspotAnqpOperatorNameDuple(pkt, &osu->desc.duple[osu->desc.numName])) { return FALSE; } else { osu->desc.numName++; } /* update remaining name length */ remDescLength -= bcm_decode_offset(pkt) - startOffset; } } list->isDecodeValid = TRUE; return TRUE; }
/* decode hotspot ANQP frame */ int bcm_decode_hspot_anqp(bcm_decode_t *pkt, int isReset, bcm_decode_hspot_anqp_t *hspot) { int nextIeOffset = 0; int ieCount = 0; WL_PRPKT("packet for hotspot ANQP decoding", bcm_decode_buf(pkt), bcm_decode_buf_length(pkt)); if (isReset) memset(hspot, 0, sizeof(*hspot)); while (nextIeOffset < bcm_decode_buf_length(pkt)) { uint16 infoId; uint16 length; uint8 oui[WFA_OUI_LEN]; uint8 type; uint8 subtype; uint8 reserved; int dataLength; uint8 *dataPtr; bcm_decode_offset_set(pkt, nextIeOffset); WL_P2PO(("decoding offset 0x%x\n", bcm_decode_offset(pkt))); /* minimum ID and length */ if (bcm_decode_remaining(pkt) < 4) { WL_P2PO(("ID and length too short\n")); break; } bcm_decode_le16(pkt, &infoId); bcm_decode_le16(pkt, &length); /* check length */ if (length > bcm_decode_remaining(pkt)) { WL_P2PO(("length exceeds packet %d > %d\n", length, bcm_decode_remaining(pkt))); break; } nextIeOffset = bcm_decode_offset(pkt) + length; /* check ID */ if (infoId != ANQP_ID_VENDOR_SPECIFIC_LIST) { WL_P2PO(("invalid ID 0x%04x\n", infoId)); continue; } if (length < HSPOT_LENGTH_OVERHEAD) { WL_P2PO(("length too short %d < %d\n", length, HSPOT_LENGTH_OVERHEAD)); continue; } /* check OUI */ if (!bcm_decode_bytes(pkt, WFA_OUI_LEN, oui) || memcmp(oui, WFA_OUI, WFA_OUI_LEN) != 0) continue; /* check type */ if (!bcm_decode_byte(pkt, &type) || type != HSPOT_ANQP_OUI_TYPE) continue; if (!bcm_decode_byte(pkt, &subtype)) continue; if (!bcm_decode_byte(pkt, &reserved)) continue; /* remaining data */ dataLength = length - HSPOT_LENGTH_OVERHEAD; dataPtr = bcm_decode_current_ptr(pkt); switch (subtype) { case HSPOT_SUBTYPE_QUERY_LIST: hspot->queryListLength = dataLength; hspot->queryListBuffer = dataPtr; break; case HSPOT_SUBTYPE_CAPABILITY_LIST: hspot->capabilityListLength = dataLength; hspot->capabilityListBuffer = dataPtr; break; case HSPOT_SUBTYPE_OPERATOR_FRIENDLY_NAME: hspot->operatorFriendlyNameLength = dataLength; hspot->operatorFriendlyNameBuffer = dataPtr; break; case HSPOT_SUBTYPE_WAN_METRICS: hspot->wanMetricsLength = dataLength; hspot->wanMetricsBuffer = dataPtr; break; case HSPOT_SUBTYPE_CONNECTION_CAPABILITY: hspot->connectionCapabilityLength = dataLength; hspot->connectionCapabilityBuffer = dataPtr; break; case HSPOT_SUBTYPE_NAI_HOME_REALM_QUERY: hspot->naiHomeRealmQueryLength = dataLength; hspot->naiHomeRealmQueryBuffer = dataPtr; break; case HSPOT_SUBTYPE_OPERATING_CLASS_INDICATION: hspot->opClassIndicationLength = dataLength; hspot->opClassIndicationBuffer = dataPtr; break; case HSPOT_SUBTYPE_ONLINE_SIGNUP_PROVIDERS: hspot->onlineSignupProvidersLength = dataLength; hspot->onlineSignupProvidersBuffer = dataPtr; break; case HSPOT_SUBTYPE_ANONYMOUS_NAI: hspot->anonymousNaiLength = dataLength; hspot->anonymousNaiBuffer = dataPtr; break; case HSPOT_SUBTYPE_ICON_REQUEST: hspot->iconRequestLength = dataLength; hspot->iconRequestBuffer = dataPtr; break; case HSPOT_SUBTYPE_ICON_BINARY_FILE: hspot->iconBinaryFileLength = dataLength; hspot->iconBinaryFileBuffer = dataPtr; break; default: WL_P2PO(("invalid subtype %d\n", subtype)); continue; break; } /* count IEs decoded */ ieCount++; } return ieCount; }
/* print decoded hotspot ANQP */ void bcm_decode_hspot_anqp_print(bcm_decode_hspot_anqp_t *hspot) { WL_P2PO(("decoded hotspot ANQP frame:\n")); if (hspot->queryListBuffer) { WL_PRPKT(" query list", hspot->queryListBuffer, hspot->queryListLength); } if (hspot->capabilityListBuffer) { WL_PRPKT(" capability list", hspot->capabilityListBuffer, hspot->capabilityListLength); } if (hspot->operatorFriendlyNameBuffer) { WL_PRPKT(" operator friendly name", hspot->operatorFriendlyNameBuffer, hspot->operatorFriendlyNameLength); } if (hspot->wanMetricsBuffer) { WL_PRPKT(" wan metrics", hspot->wanMetricsBuffer, hspot->wanMetricsLength); } if (hspot->connectionCapabilityBuffer) { WL_PRPKT(" connection capability", hspot->connectionCapabilityBuffer, hspot->connectionCapabilityLength); } if (hspot->naiHomeRealmQueryBuffer) { WL_PRPKT(" NAI home realm query", hspot->naiHomeRealmQueryBuffer, hspot->naiHomeRealmQueryLength); } if (hspot->opClassIndicationBuffer) { WL_PRPKT(" operating class indication", hspot->opClassIndicationBuffer, hspot->opClassIndicationLength); } if (hspot->onlineSignupProvidersBuffer) { WL_PRPKT(" online sign-up providers", hspot->onlineSignupProvidersBuffer, hspot->onlineSignupProvidersLength); } if (hspot->anonymousNaiBuffer) { WL_PRPKT(" anonymous NAI", hspot->anonymousNaiBuffer, hspot->anonymousNaiLength); } if (hspot->iconRequestBuffer) { WL_PRPKT(" icon request", hspot->iconRequestBuffer, hspot->iconRequestLength); } if (hspot->iconBinaryFileBuffer) { WL_PRPKT(" icon binary file", hspot->iconBinaryFileBuffer, hspot->iconBinaryFileLength); } }