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 /* We need linux/if.h for flags like IFF_UP.  Sadly, it forward declares
     23    struct sockaddr and must be included after sys/socket.h. */
     24 #include <linux/if.h>
     25 
     26 
     27 #include <android-base/logging.h>
     28 #include <android-base/unique_fd.h>
     29 
     30 namespace android {
     31 namespace wifi_system {
     32 namespace {
     33 
     34 const char kWlan0InterfaceName[] = "wlan0";
     35 
     36 bool GetIfState(const char* if_name, int sock, struct ifreq* ifr) {
     37   memset(ifr, 0, sizeof(*ifr));
     38   if (strlcpy(ifr->ifr_name, if_name, sizeof(ifr->ifr_name)) >=
     39       sizeof(ifr->ifr_name)) {
     40     LOG(ERROR) << "Interface name is too long: " << if_name;
     41     return false;
     42   }
     43 
     44   if (TEMP_FAILURE_RETRY(ioctl(sock, SIOCGIFFLAGS, ifr)) != 0) {
     45     LOG(ERROR) << "Could not read interface state for " << if_name
     46                << " (" << strerror(errno) << ")";
     47     return false;
     48   }
     49 
     50   return true;
     51 }
     52 
     53 }  // namespace
     54 
     55 bool InterfaceTool::GetUpState(const char* if_name) {
     56   base::unique_fd sock(socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0));
     57   if (sock.get() < 0) {
     58     LOG(ERROR) << "Failed to open socket to set up/down state ("
     59                << strerror(errno) << ")";
     60     return false;
     61   }
     62 
     63   struct ifreq ifr;
     64   if (!GetIfState(if_name, sock.get(), &ifr)) {
     65     return false;  // logging done internally
     66   }
     67 
     68   return ifr.ifr_flags & IFF_UP;
     69 }
     70 
     71 bool InterfaceTool::SetUpState(const char* if_name, bool request_up) {
     72   base::unique_fd sock(socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0));
     73   if (sock.get() < 0) {
     74     LOG(ERROR) << "Failed to open socket to set up/down state ("
     75                << strerror(errno) << ")";
     76     return false;
     77   }
     78 
     79   struct ifreq ifr;
     80   if (!GetIfState(if_name, sock.get(), &ifr)) {
     81     return false;  // logging done internally
     82   }
     83 
     84   const bool currently_up = ifr.ifr_flags & IFF_UP;
     85   if (currently_up == request_up) {
     86     return true;
     87   }
     88 
     89   if (request_up) {
     90     ifr.ifr_flags |= IFF_UP;
     91   } else {
     92     ifr.ifr_flags &= ~IFF_UP;
     93   }
     94 
     95   if (TEMP_FAILURE_RETRY(ioctl(sock.get(), SIOCSIFFLAGS, &ifr)) != 0) {
     96     LOG(ERROR) << "Could not set interface flags for " << if_name
     97                << " (" << strerror(errno) << ")";
     98     return false;
     99   }
    100 
    101   return true;
    102 }
    103 
    104 bool InterfaceTool::SetWifiUpState(bool request_up) {
    105   return SetUpState(kWlan0InterfaceName, request_up);
    106 }
    107 
    108 bool InterfaceTool::SetMacAddress(const char* if_name,
    109     const std::array<uint8_t, ETH_ALEN>& new_address) {
    110   struct ifreq ifr;
    111   static_assert(ETH_ALEN <= sizeof(ifr.ifr_hwaddr.sa_data),
    112     "new address is too long");
    113 
    114   base::unique_fd sock(socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0));
    115   if (sock.get() < 0) {
    116     LOG(ERROR) << "Failed to open socket to set MAC address ("
    117                << strerror(errno) << ")";
    118     return false;
    119   }
    120 
    121   if (!GetIfState(if_name, sock.get(), &ifr)) {
    122     return false;  // logging done internally
    123   }
    124 
    125   memset(&ifr.ifr_hwaddr, 0, sizeof(ifr.ifr_hwaddr));
    126   ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
    127   memcpy(ifr.ifr_hwaddr.sa_data, new_address.data(), new_address.size());
    128   if (TEMP_FAILURE_RETRY(ioctl(sock.get(), SIOCSIFHWADDR, &ifr)) != 0) {
    129     LOG(ERROR) << "Could not set interface MAC address for " << if_name
    130                << " (" << strerror(errno) << ")";
    131     return false;
    132   }
    133 
    134   return true;
    135 }
    136 
    137 }  // namespace wifi_system
    138 }  // namespace android
    139