Home | History | Annotate | Download | only in libwifi_system_iface
      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 "wifi_system/interface_tool.h"
     18 
     19 #include <net/if_arp.h>
     20 #include <netinet/in.h>
     21 #include <sys/socket.h>
     22 
     23 #include <linux/ethtool.h>
     24 /* We need linux/if.h for flags like IFF_UP.  Sadly, it forward declares
     25    struct sockaddr and must be included after sys/socket.h. */
     26 #include <linux/if.h>
     27 
     28 #include <android-base/logging.h>
     29 #include <android-base/unique_fd.h>
     30 
     31 namespace android {
     32 namespace wifi_system {
     33 namespace {
     34 
     35 const char kWlan0InterfaceName[] = "wlan0";
     36 
     37 bool GetIfState(const char* if_name, int sock, struct ifreq* ifr) {
     38   memset(ifr, 0, sizeof(*ifr));
     39   if (strlcpy(ifr->ifr_name, if_name, sizeof(ifr->ifr_name)) >=
     40       sizeof(ifr->ifr_name)) {
     41     LOG(ERROR) << "Interface name is too long: " << if_name;
     42     return false;
     43   }
     44 
     45   if (TEMP_FAILURE_RETRY(ioctl(sock, SIOCGIFFLAGS, ifr)) != 0) {
     46     LOG(ERROR) << "Could not read interface state for " << if_name
     47                << " (" << strerror(errno) << ")";
     48     return false;
     49   }
     50 
     51   return true;
     52 }
     53 
     54 }  // namespace
     55 
     56 bool InterfaceTool::GetUpState(const char* if_name) {
     57   base::unique_fd sock(socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0));
     58   if (sock.get() < 0) {
     59     LOG(ERROR) << "Failed to open socket to set up/down state ("
     60                << strerror(errno) << ")";
     61     return false;
     62   }
     63 
     64   struct ifreq ifr;
     65   if (!GetIfState(if_name, sock.get(), &ifr)) {
     66     return false;  // logging done internally
     67   }
     68 
     69   return ifr.ifr_flags & IFF_UP;
     70 }
     71 
     72 bool InterfaceTool::SetUpState(const char* if_name, bool request_up) {
     73   base::unique_fd sock(socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0));
     74   if (sock.get() < 0) {
     75     LOG(ERROR) << "Failed to open socket to set up/down state ("
     76                << strerror(errno) << ")";
     77     return false;
     78   }
     79 
     80   struct ifreq ifr;
     81   if (!GetIfState(if_name, sock.get(), &ifr)) {
     82     return false;  // logging done internally
     83   }
     84 
     85   const bool currently_up = ifr.ifr_flags & IFF_UP;
     86   if (currently_up == request_up) {
     87     return true;
     88   }
     89 
     90   if (request_up) {
     91     ifr.ifr_flags |= IFF_UP;
     92   } else {
     93     ifr.ifr_flags &= ~IFF_UP;
     94   }
     95 
     96   if (TEMP_FAILURE_RETRY(ioctl(sock.get(), SIOCSIFFLAGS, &ifr)) != 0) {
     97     LOG(ERROR) << "Could not set interface flags for " << if_name
     98                << " (" << strerror(errno) << ")";
     99     return false;
    100   }
    101 
    102   return true;
    103 }
    104 
    105 bool InterfaceTool::SetWifiUpState(bool request_up) {
    106   return SetUpState(kWlan0InterfaceName, request_up);
    107 }
    108 
    109 bool InterfaceTool::SetMacAddress(const char* if_name,
    110     const std::array<uint8_t, ETH_ALEN>& new_address) {
    111   struct ifreq ifr;
    112   static_assert(ETH_ALEN <= sizeof(ifr.ifr_hwaddr.sa_data),
    113     "new address is too long");
    114 
    115   base::unique_fd sock(socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0));
    116   if (sock.get() < 0) {
    117     LOG(ERROR) << "Failed to open socket to set MAC address ("
    118                << strerror(errno) << ")";
    119     return false;
    120   }
    121 
    122   if (!GetIfState(if_name, sock.get(), &ifr)) {
    123     return false;  // logging done internally
    124   }
    125 
    126   memset(&ifr.ifr_hwaddr, 0, sizeof(ifr.ifr_hwaddr));
    127   ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
    128   memcpy(ifr.ifr_hwaddr.sa_data, new_address.data(), new_address.size());
    129   if (TEMP_FAILURE_RETRY(ioctl(sock.get(), SIOCSIFHWADDR, &ifr)) != 0) {
    130     LOG(ERROR) << "Could not set interface MAC address for " << if_name
    131                << " (" << strerror(errno) << ")";
    132     return false;
    133   }
    134 
    135   return true;
    136 }
    137 
    138 std::array<uint8_t, ETH_ALEN> InterfaceTool::GetFactoryMacAddress(const char* if_name) {
    139   std::array<uint8_t, ETH_ALEN> paddr = {};
    140   struct ifreq ifr;
    141   struct ethtool_perm_addr *epaddr;
    142 
    143   base::unique_fd sock(socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0));
    144   if (sock.get() < 0) {
    145     LOG(ERROR) << "Failed to open socket to get factory MAC address ("
    146                << strerror(errno) << ")";
    147     return paddr;
    148   }
    149 
    150   if (!GetIfState(if_name, sock.get(), &ifr)) {
    151     return paddr;  // logging done internally
    152   }
    153 
    154   epaddr = (ethtool_perm_addr*) malloc(sizeof(struct ethtool_perm_addr) + ETH_ALEN);
    155   if (!epaddr) {
    156     LOG(ERROR) << "Failed to set memory for mac address ("
    157                << strerror(errno) << ")";
    158     return paddr;
    159   }
    160 
    161   epaddr->cmd = ETHTOOL_GPERMADDR;
    162   epaddr->size = ETH_ALEN;
    163   ifr.ifr_data = epaddr;
    164 
    165   if (TEMP_FAILURE_RETRY(ioctl(sock.get(), SIOCETHTOOL, &ifr)) != 0) {
    166     LOG(ERROR) << "Could not get factory address MAC for " << if_name
    167                << " (" << strerror(errno) << ")";
    168   } else if (epaddr->size == ETH_ALEN) {
    169     memcpy(paddr.data(), epaddr->data, ETH_ALEN);
    170   }
    171   return paddr;
    172 }
    173 
    174 }  // namespace wifi_system
    175 }  // namespace android
    176