Home | History | Annotate | Download | only in wifi_relay
      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 #include "common/commands/wifi_relay/cmd.h"
     17 
     18 namespace cvd {
     19 
     20 Cmd::Cmd() : msg_(nlmsg_alloc()) {}
     21 
     22 Cmd::Cmd(nlmsghdr* h) : msg_(nlmsg_convert(h)) {}
     23 
     24 Cmd::Cmd(nl_msg* h) {
     25   nlmsg_get(h);
     26   msg_ = h;
     27 }
     28 
     29 Cmd::~Cmd() {
     30   for (auto& msg : responses_) {
     31     nlmsg_free(msg);
     32   }
     33   nlmsg_free(msg_);
     34 }
     35 
     36 bool Cmd::OnResponse(nl_msg* msg) {
     37   // nlmsg_get increases refcount on msg, but does not return the msg
     38   // so we can't exactly use it as an argument to unique_ptr.
     39   nlmsg_get(msg);
     40   responses_.emplace_back(msg);
     41   auto hdr = nlmsg_hdr(msg);
     42 
     43   // Kernel documentation seems to be a bit misleading on this topic saying:
     44   //
     45   //     In multipart messages (multiple nlmsghdr headers with associated
     46   //     payload in one byte stream) the first and all following headers have
     47   //     the NLM_F_MULTI flag set, except for the last header which has the type
     48   //     NLMSG_DONE.
     49   //
     50   // In theory, that would make processing multi-part messages simple, but in
     51   // practice this does not seem to be true. Specifying exit criteria solely on
     52   // NLM_F_MULTI flag setting will block some, if not all calls that dump
     53   // NL80211 wifi interfaces for example.
     54   if (!(hdr->nlmsg_flags & NLM_F_MULTI) || (hdr->nlmsg_type == NLMSG_DONE) ||
     55       (hdr->nlmsg_type == NLMSG_ERROR)) {
     56     std::lock_guard<std::mutex> lock(ready_mutex_);
     57     ready_signal_.notify_all();
     58     return true;
     59   }
     60 
     61   return false;
     62 }
     63 
     64 const std::vector<nl_msg*> Cmd::Responses() const {
     65   WaitComplete();
     66   return responses_;
     67 }
     68 
     69 void Cmd::WaitComplete() const {
     70   std::unique_lock<std::mutex> lock(ready_mutex_);
     71   ready_signal_.wait(lock, [this]() { return responses_.size() > 0; });
     72 }
     73 
     74 }  // namespace cvd
     75