/* * Copyright (C) 2016 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 WIFICOND_NET_NL80211_PACKET_H_ #define WIFICOND_NET_NL80211_PACKET_H_ #include <memory> #include <vector> #include <linux/genetlink.h> #include <linux/netlink.h> #include <android-base/macros.h> #include "wificond/net/nl80211_attribute.h" namespace android { namespace wificond { // NL80211Packets are used to communicate with the cfg80211 kernel subsystem // (via the nl80211 interface). An NL80211 packet is a type of generic netlink // packet (i.e. it includes netlink and generic netlink headers). // In order to simplify the design, we also allow this class to represent a // few types of netlink control messages. In this way the API user is supposed to // call IsValid() and GetMessageType() in the first place to avoid misuse of // this class. class NL80211Packet { public: // This is used for creating a NL80211Packet from buffer. explicit NL80211Packet(const std::vector<uint8_t>& data); // This is used for creating an empty NL80211Packet to be filled later. // See comment of SetMessageType() for |type|. // See comment of SetCommand() for |command|. // See comment of SetMessageSequence() for |sequence|. // See comment of SetPortId() for |pid|. NL80211Packet(uint16_t type, uint8_t command, uint32_t sequence, uint32_t pid); // We don't copy NL80211Packet for performance reasons. // However we keep this copy constructor because it makes unit tests easy. // It prints WARNING log when this copy constructor is called. NL80211Packet(const NL80211Packet& packet); ~NL80211Packet() = default; // Returns whether a packet has consistent header fields. bool IsValid() const; // Helper functions for Netlink flags. // Requesting a dump of a kernel obejct. bool IsDump() const; // Multipart messages are used to send lists or trees of objects. // They are supposed to be parsed independently, and must not be reassembled. // Multipart messages are terminated by NLMSG_DONE, which should be returned // by GetMessageType(). bool IsMulti() const; // Getter functions. uint8_t GetCommand() const; uint16_t GetFlags() const; uint16_t GetMessageType() const; uint32_t GetMessageSequence() const; uint32_t GetPortId() const; // Caller is responsible for checking that this is a valid // NLMSG_ERROR message before calling GetErrorCode(). // Returns an error number defined in errno.h int GetErrorCode() const; const std::vector<uint8_t>& GetConstData() const; // Setter functions. // In the contexet of nl80211 messages, // |command| is one of |enum nl80211_commands| in nl80211.h void SetCommand(uint8_t command); // |flags| is set of flag bits described by NLM_F_* macros in netlink.h void AddFlag(uint16_t flag); void SetFlags(uint16_t flags); // In the context of nl80211 messages, // message type is a nl80211 message family id dynamiclly allocated by kernel. // If this is a control message, it could be one of the following value: // NLMSG_NOOP, NLMSG_ERROR, NLMSG_DONE, NLMSG_OVERRUN void SetMessageType(uint16_t message_type); // Requests should carry a sequence number incremented for each request sent. // For reply message, the sequence number is used to allow referring to a // previous message with the same sequence number. void SetMessageSequence(uint32_t message_sequemce); // Set nlmsg_pid in netlink header. // nlmsg_pid is the sender process port ID. // It is *not* associated with a process but a netlink socket. // We should use sockaddr_nl.nl_pid from sender socket. // This value should be 0 if message is from kernel. // See man 7 netlink for details. void SetPortId(uint32_t pid); void AddAttribute(const BaseNL80211Attr& attribute); // For NLA_FLAG attribute void AddFlagAttribute(int attribute_id); bool HasAttribute(int id) const; bool GetAttribute(int id, NL80211NestedAttr* attribute) const; template <typename T> bool GetAttributeValue(int id, T* value) const { std::vector<uint8_t> empty_vec; // All data in |attribute| created here will be overwritten by // GetAttribute(). So we use an empty vector to initialize it, // regardless of the fact that an empty buffer is not qualified // for creating a valid attribute. NL80211Attr<T> attribute(empty_vec); if (!GetAttribute(id, &attribute)) { return false; } *value = attribute.GetValue(); return true; } template <typename T> bool GetAttribute(int id, NL80211Attr<T>* attribute) const { uint8_t* start = nullptr; uint8_t* end = nullptr; if (!BaseNL80211Attr::GetAttributeImpl( data_.data() + NLMSG_HDRLEN + GENL_HDRLEN, data_.size() - NLMSG_HDRLEN - GENL_HDRLEN, id, &start, &end) || start == nullptr || end == nullptr) { return false; } *attribute = NL80211Attr<T>(std::vector<uint8_t>(start, end)); if (!attribute->IsValid()) { return false; } return true; } void DebugLog() const; private: std::vector<uint8_t> data_; }; } // namespace wificond } // namespace android #endif // WIFICOND_NET_NL80211_PACKET_H_