//
// Copyright (C) 2013 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.
//
#ifndef SHILL_NET_NETLINK_MESSAGE_MATCHERS_H_
#define SHILL_NET_NETLINK_MESSAGE_MATCHERS_H_
#include <base/logging.h>
#include <gmock/gmock.h>
#include "shill/net/netlink_message.h"
#include "shill/net/nl80211_message.h"
namespace shill {
// Given a netlink message, verifies that it is an Nl80211Message and verifies,
// further that it is the specified command.
MATCHER_P2(IsNl80211Command, nl80211_message_type, command, "") {
if (!arg) {
LOG(INFO) << "Null message";
return false;
}
if (arg->message_type() != nl80211_message_type) {
LOG(INFO) << "Not an nl80211 message";
return false;
}
const Nl80211Message* msg = static_cast<const Nl80211Message*>(arg);
if (msg->command() != command) {
LOG(INFO) << "Not a message of type " << command
<< " (it's a " << +msg->command() << ")";
return false;
}
return true;
}
// Given a netlink message, verifies that it is configured to disable
// wake on WiFi functionality of the NIC.
MATCHER(IsDisableWakeOnWiFiMsg, "") {
if (!arg) {
LOG(INFO) << "Null message";
return false;
}
const Nl80211Message* msg = static_cast<const Nl80211Message*>(arg);
if (msg->command() != NL80211_CMD_SET_WOWLAN) {
LOG(INFO) << "Not a NL80211_CMD_SET_WOWLAN message";
return false;
}
uint32_t wiphy;
if (!msg->const_attributes()->GetU32AttributeValue(NL80211_ATTR_WIPHY,
&wiphy)) {
LOG(INFO) << "Wiphy index not set";
return false;
}
AttributeListConstRefPtr triggers;
if (msg->const_attributes()->ConstGetNestedAttributeList(
NL80211_ATTR_WOWLAN_TRIGGERS, &triggers)) {
LOG(INFO) << "Message contains NL80211_ATTR_WOWLAN_TRIGGERS";
return false;
}
return true;
}
// Verifies that a NetlinkMessage is an NL80211_CMD_TRIGGER_SCAN message that
// contains exactly one SSID along with the requisite empty one.
MATCHER_P(HasHiddenSSID, nl80211_message_type, "") {
if (!arg) {
LOG(INFO) << "Null message";
return false;
}
if (arg->message_type() != nl80211_message_type) {
LOG(INFO) << "Not an nl80211 message";
return false;
}
const Nl80211Message* msg = reinterpret_cast<const Nl80211Message*>(arg);
if (msg->command() != NL80211_CMD_TRIGGER_SCAN) {
LOG(INFO) << "Not a NL80211_CMD_TRIGGER_SCAN message";
return false;
}
AttributeListConstRefPtr ssids;
if (!msg->const_attributes()->ConstGetNestedAttributeList(
NL80211_ATTR_SCAN_SSIDS, &ssids)) {
LOG(INFO) << "No SSID list in message";
return false;
}
ByteString ssid;
AttributeIdIterator ssid_iter(*ssids);
if (!ssids->GetRawAttributeValue(ssid_iter.GetId(), &ssid)) {
LOG(INFO) << "SSID list contains no (hidden) SSIDs";
return false;
}
// A valid Scan containing a single hidden SSID should contain
// two SSID entries: one containing the SSID we are looking for,
// and an empty entry, signifying that we also want to do a
// broadcast probe request for all non-hidden APs as well.
ByteString empty_ssid;
if (ssid_iter.AtEnd()) {
LOG(INFO) << "SSID list doesn't contain an empty SSIDs (but should)";
return false;
}
ssid_iter.Advance();
if (!ssids->GetRawAttributeValue(ssid_iter.GetId(), &empty_ssid) ||
!empty_ssid.IsEmpty()) {
LOG(INFO) << "SSID list doesn't contain an empty SSID (but should)";
return false;
}
return true;
}
// Verifies that a NetlinkMessage is an NL80211_CMD_TRIGGER_SCAN message that
// contains no SSIDs.
MATCHER_P(HasNoHiddenSSID, nl80211_message_type, "") {
if (!arg) {
LOG(INFO) << "Null message";
return false;
}
if (arg->message_type() != nl80211_message_type) {
LOG(INFO) << "Not an nl80211 message";
return false;
}
const Nl80211Message* msg = reinterpret_cast<const Nl80211Message*>(arg);
if (msg->command() != NL80211_CMD_TRIGGER_SCAN) {
LOG(INFO) << "Not a NL80211_CMD_TRIGGER_SCAN message";
return false;
}
AttributeListConstRefPtr ssids;
if (!msg->const_attributes()->ConstGetNestedAttributeList(
NL80211_ATTR_SCAN_SSIDS, &ssids)) {
return true;
}
AttributeIdIterator ssid_iter(*ssids);
if (ssid_iter.AtEnd()) {
return true;
}
LOG(INFO) << "SSID list contains at least one (hidden) SSID";
return false;
}
} // namespace shill
#endif // SHILL_NET_NETLINK_MESSAGE_MATCHERS_H_