Home | History | Annotate | Download | only in libwifi_system
      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 <netinet/in.h>
     20 #include <sys/socket.h>
     21 /* We need linux/if.h for flags like IFF_UP.  Sadly, it forward declares
     22    struct sockaddr and must be included after sys/socket.h. */
     23 #include <linux/if.h>
     24 
     25 #include <android-base/logging.h>
     26 #include <android-base/unique_fd.h>
     27 
     28 namespace android {
     29 namespace wifi_system {
     30 namespace {
     31 
     32 const char kWlan0InterfaceName[] = "wlan0";
     33 
     34 bool GetIfState(const char* if_name, int sock, struct ifreq* ifr) {
     35   memset(ifr, 0, sizeof(*ifr));
     36   if (strlcpy(ifr->ifr_name, if_name, sizeof(ifr->ifr_name)) >=
     37       sizeof(ifr->ifr_name)) {
     38     LOG(ERROR) << "Interface name is too long: " << if_name;
     39     return false;
     40   }
     41 
     42   if (TEMP_FAILURE_RETRY(ioctl(sock, SIOCGIFFLAGS, ifr)) != 0) {
     43     LOG(ERROR) << "Could not read interface state for " << if_name
     44                << " (" << strerror(errno) << ")";
     45     return false;
     46   }
     47 
     48   return true;
     49 }
     50 
     51 }  // namespace
     52 
     53 bool InterfaceTool::GetUpState(const char* if_name) {
     54   base::unique_fd sock(socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0));
     55   if (sock.get() < 0) {
     56     LOG(ERROR) << "Failed to open socket to set up/down state ("
     57                << strerror(errno) << ")";
     58     return false;
     59   }
     60 
     61   struct ifreq ifr;
     62   if (!GetIfState(if_name, sock.get(), &ifr)) {
     63     return false;  // logging done internally
     64   }
     65 
     66   return ifr.ifr_flags & IFF_UP;
     67 }
     68 
     69 bool InterfaceTool::SetUpState(const char* if_name, bool request_up) {
     70   base::unique_fd sock(socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0));
     71   if (sock.get() < 0) {
     72     LOG(ERROR) << "Failed to open socket to set up/down state ("
     73                << strerror(errno) << ")";
     74     return false;
     75   }
     76 
     77   struct ifreq ifr;
     78   if (!GetIfState(if_name, sock.get(), &ifr)) {
     79     return false;  // logging done internally
     80   }
     81 
     82   const bool currently_up = ifr.ifr_flags & IFF_UP;
     83   if (currently_up == request_up) {
     84     return true;
     85   }
     86 
     87   if (request_up) {
     88     ifr.ifr_flags |= IFF_UP;
     89   } else {
     90     ifr.ifr_flags &= ~IFF_UP;
     91   }
     92 
     93   if (TEMP_FAILURE_RETRY(ioctl(sock.get(), SIOCSIFFLAGS, &ifr)) != 0) {
     94     LOG(ERROR) << "Could not set interface flags for " << if_name
     95                << " (" << strerror(errno) << ")";
     96     return false;
     97   }
     98 
     99   return true;
    100 }
    101 
    102 bool InterfaceTool::SetWifiUpState(bool request_up) {
    103   return SetUpState(kWlan0InterfaceName, request_up);
    104 }
    105 
    106 }  // namespace wifi_system
    107 }  // namespace android
    108