/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "common/commands/wifi_relay/cmd.h" namespace cvd { Cmd::Cmd() : msg_(nlmsg_alloc()) {} Cmd::Cmd(nlmsghdr* h) : msg_(nlmsg_convert(h)) {} Cmd::Cmd(nl_msg* h) { nlmsg_get(h); msg_ = h; } Cmd::~Cmd() { for (auto& msg : responses_) { nlmsg_free(msg); } nlmsg_free(msg_); } bool Cmd::OnResponse(nl_msg* msg) { // nlmsg_get increases refcount on msg, but does not return the msg // so we can't exactly use it as an argument to unique_ptr. nlmsg_get(msg); responses_.emplace_back(msg); auto hdr = nlmsg_hdr(msg); // Kernel documentation seems to be a bit misleading on this topic saying: // // In multipart messages (multiple nlmsghdr headers with associated // payload in one byte stream) the first and all following headers have // the NLM_F_MULTI flag set, except for the last header which has the type // NLMSG_DONE. // // In theory, that would make processing multi-part messages simple, but in // practice this does not seem to be true. Specifying exit criteria solely on // NLM_F_MULTI flag setting will block some, if not all calls that dump // NL80211 wifi interfaces for example. if (!(hdr->nlmsg_flags & NLM_F_MULTI) || (hdr->nlmsg_type == NLMSG_DONE) || (hdr->nlmsg_type == NLMSG_ERROR)) { std::lock_guard<std::mutex> lock(ready_mutex_); ready_signal_.notify_all(); return true; } return false; } const std::vector<nl_msg*> Cmd::Responses() const { WaitComplete(); return responses_; } void Cmd::WaitComplete() const { std::unique_lock<std::mutex> lock(ready_mutex_); ready_signal_.wait(lock, [this]() { return responses_.size() > 0; }); } } // namespace cvd