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