Home | History | Annotate | Download | only in net
      1 /*
      2  * Copyright (C) 2016 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 "wificond/net/netlink_utils.h"
     18 
     19 #include <string>
     20 #include <vector>
     21 
     22 #include <linux/netlink.h>
     23 #include <linux/nl80211.h>
     24 
     25 #include <android-base/logging.h>
     26 
     27 #include "wificond/net/mlme_event_handler.h"
     28 #include "wificond/net/nl80211_packet.h"
     29 
     30 using std::string;
     31 using std::unique_ptr;
     32 using std::vector;
     33 
     34 namespace android {
     35 namespace wificond {
     36 
     37 namespace {
     38 
     39 uint32_t k2GHzFrequencyLowerBound = 2400;
     40 uint32_t k2GHzFrequencyUpperBound = 2500;
     41 
     42 }  // namespace
     43 NetlinkUtils::NetlinkUtils(NetlinkManager* netlink_manager)
     44     : netlink_manager_(netlink_manager) {
     45   if (!netlink_manager_->IsStarted()) {
     46     netlink_manager_->Start();
     47   }
     48 }
     49 
     50 NetlinkUtils::~NetlinkUtils() {}
     51 
     52 bool NetlinkUtils::GetWiphyIndex(uint32_t* out_wiphy_index) {
     53   NL80211Packet get_wiphy(
     54       netlink_manager_->GetFamilyId(),
     55       NL80211_CMD_GET_WIPHY,
     56       netlink_manager_->GetSequenceNumber(),
     57       getpid());
     58   get_wiphy.AddFlag(NLM_F_DUMP);
     59   vector<unique_ptr<const NL80211Packet>> response;
     60   if (!netlink_manager_->SendMessageAndGetResponses(get_wiphy, &response))  {
     61     LOG(ERROR) << "NL80211_CMD_GET_WIPHY dump failed";
     62     return false;
     63   }
     64   if (response.empty()) {
     65     LOG(DEBUG) << "No wiphy is found";
     66     return false;
     67   }
     68   for (auto& packet : response) {
     69     if (packet->GetMessageType() == NLMSG_ERROR) {
     70       LOG(ERROR) << "Receive ERROR message: "
     71                  << strerror(packet->GetErrorCode());
     72       return false;
     73     }
     74     if (packet->GetMessageType() != netlink_manager_->GetFamilyId()) {
     75       LOG(ERROR) << "Wrong message type for new interface message: "
     76                  << packet->GetMessageType();
     77       return false;
     78     }
     79     if (packet->GetCommand() != NL80211_CMD_NEW_WIPHY) {
     80       LOG(ERROR) << "Wrong command in response to "
     81                  << "a wiphy dump request: "
     82                  << static_cast<int>(packet->GetCommand());
     83       return false;
     84     }
     85     if (!packet->GetAttributeValue(NL80211_ATTR_WIPHY, out_wiphy_index)) {
     86       LOG(ERROR) << "Failed to get wiphy index from reply message";
     87       return false;
     88     }
     89   }
     90   return true;
     91 }
     92 
     93 bool NetlinkUtils::GetInterfaces(uint32_t wiphy_index,
     94                                  vector<InterfaceInfo>* interface_info) {
     95   NL80211Packet get_interfaces(
     96       netlink_manager_->GetFamilyId(),
     97       NL80211_CMD_GET_INTERFACE,
     98       netlink_manager_->GetSequenceNumber(),
     99       getpid());
    100 
    101   get_interfaces.AddFlag(NLM_F_DUMP);
    102   get_interfaces.AddAttribute(
    103       NL80211Attr<uint32_t>(NL80211_ATTR_WIPHY, wiphy_index));
    104   vector<unique_ptr<const NL80211Packet>> response;
    105   if (!netlink_manager_->SendMessageAndGetResponses(get_interfaces, &response)) {
    106     LOG(ERROR) << "NL80211_CMD_GET_INTERFACE dump failed";
    107     return false;
    108   }
    109   if (response.empty()) {
    110     LOG(ERROR) << "No interface is found";
    111     return false;
    112   }
    113   for (auto& packet : response) {
    114     if (packet->GetMessageType() == NLMSG_ERROR) {
    115       LOG(ERROR) << "Receive ERROR message: "
    116                  << strerror(packet->GetErrorCode());
    117       return false;
    118     }
    119     if (packet->GetMessageType() != netlink_manager_->GetFamilyId()) {
    120       LOG(ERROR) << "Wrong message type for new interface message: "
    121                  << packet->GetMessageType();
    122       return false;
    123     }
    124     if (packet->GetCommand() != NL80211_CMD_NEW_INTERFACE) {
    125       LOG(ERROR) << "Wrong command in response to "
    126                  << "an interface dump request: "
    127                  << static_cast<int>(packet->GetCommand());
    128       return false;
    129     }
    130 
    131     // In some situations, it has been observed that the kernel tells us
    132     // about a pseudo interface that does not have a real netdev.  In this
    133     // case, responses will have a NL80211_ATTR_WDEV, and not the expected
    134     // IFNAME/IFINDEX. In this case we just skip these pseudo interfaces.
    135     uint32_t if_index;
    136     if (!packet->GetAttributeValue(NL80211_ATTR_IFINDEX, &if_index)) {
    137       LOG(DEBUG) << "Failed to get interface index";
    138       continue;
    139     }
    140 
    141     // Today we don't check NL80211_ATTR_IFTYPE because at this point of time
    142     // driver always reports that interface is in STATION mode. Even when we
    143     // are asking interfaces infomation on behalf of tethering, it is still so
    144     // because hostapd is supposed to set interface to AP mode later.
    145 
    146     string if_name;
    147     if (!packet->GetAttributeValue(NL80211_ATTR_IFNAME, &if_name)) {
    148       LOG(WARNING) << "Failed to get interface name";
    149       continue;
    150     }
    151 
    152     vector<uint8_t> if_mac_addr;
    153     if (!packet->GetAttributeValue(NL80211_ATTR_MAC, &if_mac_addr)) {
    154       LOG(WARNING) << "Failed to get interface mac address";
    155       continue;
    156     }
    157 
    158     interface_info->emplace_back(if_index, if_name, if_mac_addr);
    159   }
    160 
    161   return true;
    162 }
    163 
    164 bool NetlinkUtils::SetInterfaceMode(uint32_t interface_index,
    165                                     InterfaceMode mode) {
    166   uint32_t set_to_mode = NL80211_IFTYPE_UNSPECIFIED;
    167   if (mode == STATION_MODE) {
    168     set_to_mode = NL80211_IFTYPE_STATION;
    169   } else {
    170     LOG(ERROR) << "Unexpected mode for interface with index: "
    171                << interface_index;
    172     return false;
    173   }
    174   NL80211Packet set_interface_mode(
    175       netlink_manager_->GetFamilyId(),
    176       NL80211_CMD_SET_INTERFACE,
    177       netlink_manager_->GetSequenceNumber(),
    178       getpid());
    179   // Force an ACK response upon success.
    180   set_interface_mode.AddFlag(NLM_F_ACK);
    181 
    182   set_interface_mode.AddAttribute(
    183       NL80211Attr<uint32_t>(NL80211_ATTR_IFINDEX, interface_index));
    184   set_interface_mode.AddAttribute(
    185       NL80211Attr<uint32_t>(NL80211_ATTR_IFTYPE, set_to_mode));
    186 
    187   if (!netlink_manager_->SendMessageAndGetAck(set_interface_mode)) {
    188     LOG(ERROR) << "NL80211_CMD_SET_INTERFACE failed";
    189     return false;
    190   }
    191 
    192   return true;
    193 }
    194 
    195 bool NetlinkUtils::GetWiphyInfo(
    196     uint32_t wiphy_index,
    197     BandInfo* out_band_info,
    198     ScanCapabilities* out_scan_capabilities,
    199     WiphyFeatures* out_wiphy_features) {
    200   NL80211Packet get_wiphy(
    201       netlink_manager_->GetFamilyId(),
    202       NL80211_CMD_GET_WIPHY,
    203       netlink_manager_->GetSequenceNumber(),
    204       getpid());
    205   get_wiphy.AddAttribute(NL80211Attr<uint32_t>(NL80211_ATTR_WIPHY, wiphy_index));
    206   unique_ptr<const NL80211Packet> response;
    207   if (!netlink_manager_->SendMessageAndGetSingleResponse(get_wiphy,
    208                                                          &response)) {
    209     LOG(ERROR) << "NL80211_CMD_GET_WIPHY failed";
    210     return false;
    211   }
    212   if (response->GetCommand() != NL80211_CMD_NEW_WIPHY) {
    213     LOG(ERROR) << "Wrong command in response to a get wiphy request: "
    214                << static_cast<int>(response->GetCommand());
    215     return false;
    216   }
    217   if (!ParseBandInfo(response.get(), out_band_info) ||
    218       !ParseScanCapabilities(response.get(), out_scan_capabilities)) {
    219     return false;
    220   }
    221   uint32_t feature_flags;
    222   if (!response->GetAttributeValue(NL80211_ATTR_FEATURE_FLAGS,
    223                                    &feature_flags)) {
    224     LOG(ERROR) << "Failed to get NL80211_ATTR_FEATURE_FLAGS";
    225     return false;
    226   }
    227   *out_wiphy_features = WiphyFeatures(feature_flags);
    228   return true;
    229 }
    230 
    231 bool NetlinkUtils::ParseScanCapabilities(
    232     const NL80211Packet* const packet,
    233     ScanCapabilities* out_scan_capabilities) {
    234   uint8_t max_num_scan_ssids;
    235   if (!packet->GetAttributeValue(NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
    236                                    &max_num_scan_ssids)) {
    237     LOG(ERROR) << "Failed to get the capacity of maximum number of scan ssids";
    238     return false;
    239   }
    240 
    241   uint8_t max_num_sched_scan_ssids;
    242   if (!packet->GetAttributeValue(NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
    243                                  &max_num_sched_scan_ssids)) {
    244     LOG(ERROR) << "Failed to get the capacity of "
    245                << "maximum number of scheduled scan ssids";
    246     return false;
    247   }
    248 
    249   // Use default value 0 for scan plan capabilities if attributes are missing.
    250   uint32_t max_num_scan_plans = 0;
    251   packet->GetAttributeValue(NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS,
    252                             &max_num_scan_plans);
    253   uint32_t max_scan_plan_interval = 0;
    254   packet->GetAttributeValue(NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL,
    255                             &max_scan_plan_interval);
    256   uint32_t max_scan_plan_iterations = 0;
    257   packet->GetAttributeValue(NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS,
    258                             &max_scan_plan_iterations);
    259 
    260   uint8_t max_match_sets;
    261   if (!packet->GetAttributeValue(NL80211_ATTR_MAX_MATCH_SETS,
    262                                    &max_match_sets)) {
    263     LOG(ERROR) << "Failed to get the capacity of maximum number of match set"
    264                << "of a scheduled scan";
    265     return false;
    266   }
    267   *out_scan_capabilities = ScanCapabilities(max_num_scan_ssids,
    268                                             max_num_sched_scan_ssids,
    269                                             max_match_sets,
    270                                             max_num_scan_plans,
    271                                             max_scan_plan_interval,
    272                                             max_scan_plan_iterations);
    273   return true;
    274 }
    275 
    276 bool NetlinkUtils::ParseBandInfo(const NL80211Packet* const packet,
    277                                  BandInfo* out_band_info) {
    278 
    279   NL80211NestedAttr bands_attr(0);
    280   if (!packet->GetAttribute(NL80211_ATTR_WIPHY_BANDS, &bands_attr)) {
    281     LOG(ERROR) << "Failed to get NL80211_ATTR_WIPHY_BANDS";
    282     return false;
    283   }
    284   vector<NL80211NestedAttr> bands;
    285   if (!bands_attr.GetListOfNestedAttributes(&bands)) {
    286     LOG(ERROR) << "Failed to get bands within NL80211_ATTR_WIPHY_BANDS";
    287     return false;
    288   }
    289   vector<uint32_t> frequencies_2g;
    290   vector<uint32_t> frequencies_5g;
    291   vector<uint32_t> frequencies_dfs;
    292   for (unsigned int band_index = 0; band_index < bands.size(); band_index++) {
    293     NL80211NestedAttr freqs_attr(0);
    294     if (!bands[band_index].GetAttribute(NL80211_BAND_ATTR_FREQS, &freqs_attr)) {
    295       LOG(DEBUG) << "Failed to get NL80211_BAND_ATTR_FREQS";
    296       continue;
    297     }
    298     vector<NL80211NestedAttr> freqs;
    299     if (!freqs_attr.GetListOfNestedAttributes(&freqs)) {
    300       LOG(ERROR) << "Failed to get frequencies within NL80211_BAND_ATTR_FREQS";
    301       continue;
    302     }
    303     for (auto& freq : freqs) {
    304       uint32_t frequency_value;
    305       if (!freq.GetAttributeValue(NL80211_FREQUENCY_ATTR_FREQ,
    306                                   &frequency_value)) {
    307         LOG(DEBUG) << "Failed to get NL80211_FREQUENCY_ATTR_FREQ";
    308         continue;
    309       }
    310       // Channel is disabled in current regulatory domain.
    311       if (freq.HasAttribute(NL80211_FREQUENCY_ATTR_DISABLED)) {
    312         continue;
    313       }
    314       // If this is an available/usable DFS frequency, we should save it to
    315       // DFS frequencies list.
    316       uint32_t dfs_state;
    317       if (freq.GetAttributeValue(NL80211_FREQUENCY_ATTR_DFS_STATE,
    318                                  &dfs_state) &&
    319           (dfs_state == NL80211_DFS_AVAILABLE ||
    320                dfs_state == NL80211_DFS_USABLE)) {
    321         frequencies_dfs.push_back(frequency_value);
    322       } else {
    323         // Since there is no guarantee for the order of band attributes,
    324         // we do some math here.
    325         if (frequency_value > k2GHzFrequencyLowerBound &&
    326             frequency_value < k2GHzFrequencyUpperBound) {
    327           frequencies_2g.push_back(frequency_value);
    328         } else {
    329           frequencies_5g.push_back(frequency_value);
    330         }
    331       }
    332     }
    333   }
    334   *out_band_info = BandInfo(frequencies_2g, frequencies_5g, frequencies_dfs);
    335   return true;
    336 }
    337 
    338 bool NetlinkUtils::GetStationInfo(uint32_t interface_index,
    339                                   const vector<uint8_t>& mac_address,
    340                                   StationInfo* out_station_info) {
    341   NL80211Packet get_station(
    342       netlink_manager_->GetFamilyId(),
    343       NL80211_CMD_GET_STATION,
    344       netlink_manager_->GetSequenceNumber(),
    345       getpid());
    346   get_station.AddAttribute(NL80211Attr<uint32_t>(NL80211_ATTR_IFINDEX,
    347                                                  interface_index));
    348   get_station.AddAttribute(NL80211Attr<vector<uint8_t>>(NL80211_ATTR_MAC,
    349                                                         mac_address));
    350 
    351   unique_ptr<const NL80211Packet> response;
    352   if (!netlink_manager_->SendMessageAndGetSingleResponse(get_station,
    353                                                          &response)) {
    354     LOG(ERROR) << "NL80211_CMD_GET_STATION failed";
    355     return false;
    356   }
    357   if (response->GetCommand() != NL80211_CMD_NEW_STATION) {
    358     LOG(ERROR) << "Wrong command in response to a get station request: "
    359                << static_cast<int>(response->GetCommand());
    360     return false;
    361   }
    362   NL80211NestedAttr sta_info(0);
    363   if (!response->GetAttribute(NL80211_ATTR_STA_INFO, &sta_info)) {
    364     LOG(ERROR) << "Failed to get NL80211_ATTR_STA_INFO";
    365     return false;
    366   }
    367   int32_t tx_good, tx_bad;
    368   if (!sta_info.GetAttributeValue(NL80211_STA_INFO_TX_PACKETS, &tx_good)) {
    369     LOG(ERROR) << "Failed to get NL80211_STA_INFO_TX_PACKETS";
    370     return false;
    371   }
    372   if (!sta_info.GetAttributeValue(NL80211_STA_INFO_TX_FAILED, &tx_bad)) {
    373     LOG(ERROR) << "Failed to get NL80211_STA_INFO_TX_FAILED";
    374     return false;
    375   }
    376   int8_t current_rssi;
    377   if (!sta_info.GetAttributeValue(NL80211_STA_INFO_SIGNAL, &current_rssi)) {
    378     LOG(ERROR) << "Failed to get NL80211_STA_INFO_SIGNAL";
    379     return false;
    380   }
    381   NL80211NestedAttr tx_bitrate_attr(0);
    382   if (!sta_info.GetAttribute(NL80211_STA_INFO_TX_BITRATE,
    383                             &tx_bitrate_attr)) {
    384     LOG(ERROR) << "Failed to get NL80211_STA_INFO_TX_BITRATE";
    385     return false;
    386   }
    387   uint32_t tx_bitrate;
    388   if (!tx_bitrate_attr.GetAttributeValue(NL80211_RATE_INFO_BITRATE32,
    389                                          &tx_bitrate)) {
    390     LOG(ERROR) << "Failed to get NL80211_RATE_INFO_BITRATE32";
    391     return false;
    392   }
    393 
    394   *out_station_info = StationInfo(tx_good, tx_bad, tx_bitrate, current_rssi);
    395   return true;
    396 }
    397 
    398 void NetlinkUtils::SubscribeMlmeEvent(uint32_t interface_index,
    399                                       MlmeEventHandler* handler) {
    400   netlink_manager_->SubscribeMlmeEvent(interface_index, handler);
    401 }
    402 
    403 void NetlinkUtils::UnsubscribeMlmeEvent(uint32_t interface_index) {
    404   netlink_manager_->UnsubscribeMlmeEvent(interface_index);
    405 }
    406 
    407 void NetlinkUtils::SubscribeRegDomainChange(
    408     uint32_t wiphy_index,
    409     OnRegDomainChangedHandler handler) {
    410   netlink_manager_->SubscribeRegDomainChange(wiphy_index, handler);
    411 }
    412 
    413 void NetlinkUtils::UnsubscribeRegDomainChange(uint32_t wiphy_index) {
    414   netlink_manager_->UnsubscribeRegDomainChange(wiphy_index);
    415 }
    416 
    417 void NetlinkUtils::SubscribeStationEvent(uint32_t interface_index,
    418                                          OnStationEventHandler handler) {
    419   netlink_manager_->SubscribeStationEvent(interface_index, handler);
    420 }
    421 
    422 void NetlinkUtils::UnsubscribeStationEvent(uint32_t interface_index) {
    423   netlink_manager_->UnsubscribeStationEvent(interface_index);
    424 }
    425 
    426 }  // namespace wificond
    427 }  // namespace android
    428