/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <algorithm>
#include <cctype>
#include "chre/apps/wifi_offload/utility.h"
#include "chre/apps/wifi_offload/wifi_offload.h"
namespace wifi_offload {
namespace utility {
namespace {
// The length of a string SSID with null-terminator.
constexpr size_t kMaxSsidStrLen = CHRE_WIFI_SSID_MAX_LEN + 1;
// The length of a formatted BSSID string in XX:XX:XX:XX:XX:XX\0 format.
constexpr size_t kBssidStrLen = 18;
bool ParseSsidToStr(const uint8_t *ssid, size_t ssid_len, char *ssid_str,
size_t ssid_str_len) {
if (ssid_str_len < ssid_len + 1) {
return false;
}
// Verify that the ssid is entirely printable characters and ASCII spaces.
for (uint8_t i = 0; i < ssid_len; i++) {
if (!std::isgraph(ssid[i]) && ssid[i] != ' ') {
return false;
}
}
std::memcpy(ssid_str, ssid, ssid_len);
ssid_str[ssid_len] = '\0';
return true;
}
bool ParseBssidToStr(const uint8_t bssid[CHRE_WIFI_BSSID_LEN], char *bssid_str,
size_t bssid_str_len) {
if (bssid_str_len < kBssidStrLen) {
return false;
}
const char *kFormat = "%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8
":%02" PRIx8 ":%02" PRIx8;
std::snprintf(bssid_str, bssid_str_len, kFormat, bssid[0], bssid[1], bssid[2],
bssid[3], bssid[4], bssid[5]);
return true;
}
const char *ParseChreWifiBand(uint8_t band) {
switch (band) {
case CHRE_WIFI_BAND_2_4_GHZ:
return "2.4GHz";
case CHRE_WIFI_BAND_5_GHZ:
return "5GHz";
default:
return "<invalid>";
}
}
} // namespace
int Ieee80211FrequencyToChannel(int freq) {
/* see 802.11-2007 17.3.8.3.2 and Annex J */
if (freq == 2484)
return 14;
else if (freq < 2484)
return (freq - 2407) / 5;
else if (freq >= 4910 && freq <= 4980)
return (freq - 4000) / 5;
else if (freq <= 45000) /* DMG band lower limit */
return (freq - 5000) / 5;
else if (freq >= 58320 && freq <= 64800)
return (freq - 56160) / 2160;
else
return 0;
}
void LogSsid(const uint8_t *ssid, uint8_t ssid_len) {
const char *ssid_str = "<non-printable>";
char ssid_buffer[kMaxSsidStrLen];
if (ssid_len == 0) {
ssid_str = "<empty>";
} else if (ParseSsidToStr(ssid, ssid_len, ssid_buffer, kMaxSsidStrLen)) {
ssid_str = ssid_buffer;
} else {
// ssid has non-printable ASCII chars, parse in hex format
char ssid_hex_buffer[CHRE_WIFI_SSID_MAX_LEN * 3];
char *buf_ptr = ssid_hex_buffer;
for (size_t i = 0; i < ssid_len; i++) {
buf_ptr += std::sprintf(buf_ptr, "%02" PRIx8 ":", ssid[i]);
}
buf_ptr[-1] = '\0';
ssid_str = ssid_hex_buffer;
}
LOGI(" ssid: %s", ssid_str);
}
void LogBssid(const uint8_t *bssid) {
const char *bssid_str = "<non-printable>";
char bssidBuffer[kBssidStrLen];
if (ParseBssidToStr(bssid, bssidBuffer, kBssidStrLen)) {
bssid_str = bssidBuffer;
}
LOGI(" bssid: %s", bssid_str);
}
void LogChreScanResult(const chreWifiScanResult &result) {
LOGI("chreWifiScanResult:");
LogSsid(result.ssid, result.ssidLen);
LOGI(" age (ms): %" PRIu32, result.ageMs);
LOGI(" capability info: 0x%" PRIx16, result.capabilityInfo);
LogBssid(result.bssid);
LOGI(" flags: 0x%" PRIx8, result.flags);
LOGI(" rssi: %" PRId8 "dBm", result.rssi);
LOGI(" band: %s (%" PRIu8 ")", ParseChreWifiBand(result.band), result.band);
LOGI(" primary channel: %" PRIu32, result.primaryChannel);
LOGI(" center frequency primary: %" PRIu32, result.centerFreqPrimary);
LOGI(" center frequency secondary: %" PRIu32, result.centerFreqSecondary);
LOGI(" channel width: %" PRIu8, result.channelWidth);
LOGI(" security mode: %" PRIu8, result.securityMode);
}
const char *GetErrorCodeName(ErrorCode error_code) {
switch (error_code) {
case SUCCESS:
return "SUCCESS";
case FAILED_TO_ALLOCATE_MESSAGE_BUFFER:
return "FAILED_TO_ALLOCATE_MESSAGE_BUFFER";
case FAILED_TO_SERIALIZE_MESSAGE:
return "FAILED_TO_SERIALIZE_MESSAGE";
case FAILED_TO_SEND_MESSAGE:
return "FAILED_TO_SEND_MESSAGE";
case FAILED_TO_DESERIALIZE_SCAN_CONFIG:
return "FAILED_TO_DESERIALIZE_SCAN_CONFIG";
case INVALID_SUBSCRIBE_MESSAGE_SIZE:
return "INVALID_SUBSCRIBE_MESSAGE_SIZE";
case SCAN_CONFIG_NOT_INITIALIZED:
return "SCAN_CONFIG_NOT_INITIALIZED";
case UNSPECIFIED_HOST_ENDPOINT:
return "UNSPECIFIED_HOST_ENDPOINT";
case FAILED_TO_SEND_SCAN_RESULTS:
return "FAILED_TO_SEND_SCAN_RESULTS";
case FAILED_TO_SEND_SCAN_STATS:
return "FAILED_TO_SEND_SCAN_STATS";
case SCAN_MONITORING_NOT_SUPPORTED:
return "SCAN_MONITORING_NOT_SUPPORTED";
case FAILED_TO_START_SCAN_MONITORING:
return "FAILED_TO_START_SCAN_MONITORING";
case FAILED_TO_STOP_SCAN_MONITORING:
return "FAILED_TO_STOP_SCAN_MONITORING";
case FAILED_TO_CONFIGURE_SCAN_MONITORING_ASYNC:
return "FAILED_TO_CONFIGURE_SCAN_MONITORING_ASYNC";
case ONDEMAND_SCAN_NOT_SUPPORTED:
return "ONDEMAND_SCAN_NOT_SUPPORTED";
case FAILED_TO_SEND_ONDEMAND_SCAN_REQUEST:
return "FAILED_TO_SEND_ONDEMAND_SCAN_REQUEST";
case FAILED_TO_SEND_ONDEMAND_SCAN_REQUEST_ASYNC:
return "FAILED_TO_SEND_ONDEMAND_SCAN_REQUEST_ASYNC";
case OUT_OF_ORDER_SCAN_RESULTS:
return "OUT_OF_ORDER_SCAN_RESULTS";
case INCOMPLETE_SCAN_RESULTS_BEFORE_SCAN_REQUEST:
return "INCOMPLETE_SCAN_RESULTS_BEFORE_SCAN_REQUEST";
case FAILED_TO_SET_SCAN_TIMER:
return "FAILED_TO_SET_SCAN_TIMER";
default:
return "UNKNOWN_ERROR";
}
}
} // namespace utility
} // namespace wifi_offload