1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <algorithm>
18#include <cctype>
19
20#include "chre/apps/wifi_offload/utility.h"
21#include "chre/apps/wifi_offload/wifi_offload.h"
22
23namespace wifi_offload {
24namespace utility {
25namespace {
26
27// The length of a string SSID with null-terminator.
28constexpr size_t kMaxSsidStrLen = CHRE_WIFI_SSID_MAX_LEN + 1;
29// The length of a formatted BSSID string in XX:XX:XX:XX:XX:XX\0 format.
30constexpr size_t kBssidStrLen = 18;
31
32bool ParseSsidToStr(const uint8_t *ssid, size_t ssid_len, char *ssid_str,
33                    size_t ssid_str_len) {
34  if (ssid_str_len < ssid_len + 1) {
35    return false;
36  }
37  // Verify that the ssid is entirely printable characters and ASCII spaces.
38  for (uint8_t i = 0; i < ssid_len; i++) {
39    if (!std::isgraph(ssid[i]) && ssid[i] != ' ') {
40      return false;
41    }
42  }
43
44  std::memcpy(ssid_str, ssid, ssid_len);
45  ssid_str[ssid_len] = '\0';
46  return true;
47}
48
49bool ParseBssidToStr(const uint8_t bssid[CHRE_WIFI_BSSID_LEN], char *bssid_str,
50                     size_t bssid_str_len) {
51  if (bssid_str_len < kBssidStrLen) {
52    return false;
53  }
54
55  const char *kFormat = "%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8
56                        ":%02" PRIx8 ":%02" PRIx8;
57  std::snprintf(bssid_str, bssid_str_len, kFormat, bssid[0], bssid[1], bssid[2],
58                bssid[3], bssid[4], bssid[5]);
59  return true;
60}
61
62const char *ParseChreWifiBand(uint8_t band) {
63  switch (band) {
64    case CHRE_WIFI_BAND_2_4_GHZ:
65      return "2.4GHz";
66    case CHRE_WIFI_BAND_5_GHZ:
67      return "5GHz";
68    default:
69      return "<invalid>";
70  }
71}
72
73}  // namespace
74
75int Ieee80211FrequencyToChannel(int freq) {
76  /* see 802.11-2007 17.3.8.3.2 and Annex J */
77  if (freq == 2484)
78    return 14;
79  else if (freq < 2484)
80    return (freq - 2407) / 5;
81  else if (freq >= 4910 && freq <= 4980)
82    return (freq - 4000) / 5;
83  else if (freq <= 45000) /* DMG band lower limit */
84    return (freq - 5000) / 5;
85  else if (freq >= 58320 && freq <= 64800)
86    return (freq - 56160) / 2160;
87  else
88    return 0;
89}
90
91void LogSsid(const uint8_t *ssid, uint8_t ssid_len) {
92  const char *ssid_str = "<non-printable>";
93  char ssid_buffer[kMaxSsidStrLen];
94  if (ssid_len == 0) {
95    ssid_str = "<empty>";
96  } else if (ParseSsidToStr(ssid, ssid_len, ssid_buffer, kMaxSsidStrLen)) {
97    ssid_str = ssid_buffer;
98  } else {
99    // ssid has non-printable ASCII chars, parse in hex format
100    char ssid_hex_buffer[CHRE_WIFI_SSID_MAX_LEN * 3];
101    char *buf_ptr = ssid_hex_buffer;
102    for (size_t i = 0; i < ssid_len; i++) {
103      buf_ptr += std::sprintf(buf_ptr, "%02" PRIx8 ":", ssid[i]);
104    }
105    buf_ptr[-1] = '\0';
106    ssid_str = ssid_hex_buffer;
107  }
108  LOGI("  ssid: %s", ssid_str);
109}
110
111void LogBssid(const uint8_t *bssid) {
112  const char *bssid_str = "<non-printable>";
113  char bssidBuffer[kBssidStrLen];
114  if (ParseBssidToStr(bssid, bssidBuffer, kBssidStrLen)) {
115    bssid_str = bssidBuffer;
116  }
117  LOGI("  bssid: %s", bssid_str);
118}
119
120void LogChreScanResult(const chreWifiScanResult &result) {
121  LOGI("chreWifiScanResult:");
122  LogSsid(result.ssid, result.ssidLen);
123  LOGI("  age (ms): %" PRIu32, result.ageMs);
124  LOGI("  capability info: 0x%" PRIx16, result.capabilityInfo);
125  LogBssid(result.bssid);
126  LOGI("  flags: 0x%" PRIx8, result.flags);
127  LOGI("  rssi: %" PRId8 "dBm", result.rssi);
128  LOGI("  band: %s (%" PRIu8 ")", ParseChreWifiBand(result.band), result.band);
129  LOGI("  primary channel: %" PRIu32, result.primaryChannel);
130  LOGI("  center frequency primary: %" PRIu32, result.centerFreqPrimary);
131  LOGI("  center frequency secondary: %" PRIu32, result.centerFreqSecondary);
132  LOGI("  channel width: %" PRIu8, result.channelWidth);
133  LOGI("  security mode: %" PRIu8, result.securityMode);
134}
135
136const char *GetErrorCodeName(ErrorCode error_code) {
137  switch (error_code) {
138    case SUCCESS:
139      return "SUCCESS";
140    case FAILED_TO_ALLOCATE_MESSAGE_BUFFER:
141      return "FAILED_TO_ALLOCATE_MESSAGE_BUFFER";
142    case FAILED_TO_SERIALIZE_MESSAGE:
143      return "FAILED_TO_SERIALIZE_MESSAGE";
144    case FAILED_TO_SEND_MESSAGE:
145      return "FAILED_TO_SEND_MESSAGE";
146    case FAILED_TO_DESERIALIZE_SCAN_CONFIG:
147      return "FAILED_TO_DESERIALIZE_SCAN_CONFIG";
148    case INVALID_SUBSCRIBE_MESSAGE_SIZE:
149      return "INVALID_SUBSCRIBE_MESSAGE_SIZE";
150    case SCAN_CONFIG_NOT_INITIALIZED:
151      return "SCAN_CONFIG_NOT_INITIALIZED";
152    case UNSPECIFIED_HOST_ENDPOINT:
153      return "UNSPECIFIED_HOST_ENDPOINT";
154    case FAILED_TO_SEND_SCAN_RESULTS:
155      return "FAILED_TO_SEND_SCAN_RESULTS";
156    case FAILED_TO_SEND_SCAN_STATS:
157      return "FAILED_TO_SEND_SCAN_STATS";
158    case SCAN_MONITORING_NOT_SUPPORTED:
159      return "SCAN_MONITORING_NOT_SUPPORTED";
160    case FAILED_TO_START_SCAN_MONITORING:
161      return "FAILED_TO_START_SCAN_MONITORING";
162    case FAILED_TO_STOP_SCAN_MONITORING:
163      return "FAILED_TO_STOP_SCAN_MONITORING";
164    case FAILED_TO_CONFIGURE_SCAN_MONITORING_ASYNC:
165      return "FAILED_TO_CONFIGURE_SCAN_MONITORING_ASYNC";
166    case ONDEMAND_SCAN_NOT_SUPPORTED:
167      return "ONDEMAND_SCAN_NOT_SUPPORTED";
168    case FAILED_TO_SEND_ONDEMAND_SCAN_REQUEST:
169      return "FAILED_TO_SEND_ONDEMAND_SCAN_REQUEST";
170    case FAILED_TO_SEND_ONDEMAND_SCAN_REQUEST_ASYNC:
171      return "FAILED_TO_SEND_ONDEMAND_SCAN_REQUEST_ASYNC";
172    case OUT_OF_ORDER_SCAN_RESULTS:
173      return "OUT_OF_ORDER_SCAN_RESULTS";
174    case INCOMPLETE_SCAN_RESULTS_BEFORE_SCAN_REQUEST:
175      return "INCOMPLETE_SCAN_RESULTS_BEFORE_SCAN_REQUEST";
176    case FAILED_TO_SET_SCAN_TIMER:
177      return "FAILED_TO_SET_SCAN_TIMER";
178    default:
179      return "UNKNOWN_ERROR";
180  }
181}
182
183}  // namespace utility
184}  // namespace wifi_offload
185