#include "wifi_hal.h" | |
#include "common.h" | |
#include "sync.h" | |
class WifiEvent | |
{ | |
/* TODO: remove this when nl headers are updated */ | |
static const unsigned NL80211_ATTR_MAX_INTERNAL = 256; | |
private: | |
struct nl_msg *mMsg; | |
struct genlmsghdr *mHeader; | |
struct nlattr *mAttributes[NL80211_ATTR_MAX_INTERNAL + 1]; | |
public: | |
WifiEvent(nl_msg *msg) { | |
mMsg = msg; | |
mHeader = NULL; | |
memset(mAttributes, 0, sizeof(mAttributes)); | |
} | |
~WifiEvent() { | |
/* don't destroy mMsg; it doesn't belong to us */ | |
} | |
void log(); | |
int parse(); | |
genlmsghdr *header() { | |
return mHeader; | |
} | |
int get_cmd() { | |
return mHeader->cmd; | |
} | |
int get_vendor_id() { | |
return get_u32(NL80211_ATTR_VENDOR_ID); | |
} | |
int get_vendor_subcmd() { | |
return get_u32(NL80211_ATTR_VENDOR_SUBCMD); | |
} | |
void *get_vendor_data() { | |
return get_data(NL80211_ATTR_VENDOR_DATA); | |
} | |
int get_vendor_data_len() { | |
return get_len(NL80211_ATTR_VENDOR_DATA); | |
} | |
const char *get_cmdString(); | |
nlattr ** attributes() { | |
return mAttributes; | |
} | |
nlattr *get_attribute(int attribute) { | |
return mAttributes[attribute]; | |
} | |
uint8_t get_u8(int attribute) { | |
return mAttributes[attribute] ? nla_get_u8(mAttributes[attribute]) : 0; | |
} | |
uint16_t get_u16(int attribute) { | |
return mAttributes[attribute] ? nla_get_u16(mAttributes[attribute]) : 0; | |
} | |
uint32_t get_u32(int attribute) { | |
return mAttributes[attribute] ? nla_get_u32(mAttributes[attribute]) : 0; | |
} | |
uint64_t get_u64(int attribute) { | |
return mAttributes[attribute] ? nla_get_u64(mAttributes[attribute]) : 0; | |
} | |
int get_len(int attribute) { | |
return mAttributes[attribute] ? nla_len(mAttributes[attribute]) : 0; | |
} | |
void *get_data(int attribute) { | |
return mAttributes[attribute] ? nla_data(mAttributes[attribute]) : NULL; | |
} | |
private: | |
WifiEvent(const WifiEvent&); // hide copy constructor to prevent copies | |
}; | |
class nl_iterator { | |
struct nlattr *pos; | |
int rem; | |
public: | |
nl_iterator(struct nlattr *attr) { | |
pos = (struct nlattr *)nla_data(attr); | |
rem = nla_len(attr); | |
} | |
bool has_next() { | |
return nla_ok(pos, rem); | |
} | |
void next() { | |
pos = (struct nlattr *)nla_next(pos, &(rem)); | |
} | |
struct nlattr *get() { | |
return pos; | |
} | |
uint16_t get_type() { | |
return pos->nla_type; | |
} | |
uint8_t get_u8() { | |
return nla_get_u8(pos); | |
} | |
uint16_t get_u16() { | |
return nla_get_u16(pos); | |
} | |
uint32_t get_u32() { | |
return nla_get_u32(pos); | |
} | |
uint64_t get_u64() { | |
return nla_get_u64(pos); | |
} | |
void* get_data() { | |
return nla_data(pos); | |
} | |
int get_len() { | |
return nla_len(pos); | |
} | |
private: | |
nl_iterator(const nl_iterator&); // hide copy constructor to prevent copies | |
}; | |
class WifiRequest | |
{ | |
private: | |
int mFamily; | |
int mIface; | |
struct nl_msg *mMsg; | |
public: | |
WifiRequest(int family) { | |
mMsg = NULL; | |
mFamily = family; | |
mIface = -1; | |
} | |
WifiRequest(int family, int iface) { | |
mMsg = NULL; | |
mFamily = family; | |
mIface = iface; | |
} | |
~WifiRequest() { | |
destroy(); | |
} | |
void destroy() { | |
if (mMsg) { | |
nlmsg_free(mMsg); | |
mMsg = NULL; | |
} | |
} | |
nl_msg *getMessage() { | |
return mMsg; | |
} | |
/* Command assembly helpers */ | |
int create(int family, uint8_t cmd, int flags, int hdrlen); | |
int create(uint8_t cmd) { | |
return create(mFamily, cmd, 0, 0); | |
} | |
int create(uint32_t id, int subcmd); | |
int put(int attribute, void *ptr, unsigned len) { | |
return nla_put(mMsg, attribute, len, ptr); | |
} | |
int put_u8(int attribute, uint8_t value) { | |
return nla_put(mMsg, attribute, sizeof(value), &value); | |
} | |
int put_u16(int attribute, uint16_t value) { | |
return nla_put(mMsg, attribute, sizeof(value), &value); | |
} | |
int put_u32(int attribute, uint32_t value) { | |
return nla_put(mMsg, attribute, sizeof(value), &value); | |
} | |
int put_u64(int attribute, uint64_t value) { | |
return nla_put(mMsg, attribute, sizeof(value), &value); | |
} | |
int put_string(int attribute, const char *value) { | |
return nla_put(mMsg, attribute, strlen(value) + 1, value); | |
} | |
int put_addr(int attribute, mac_addr value) { | |
return nla_put(mMsg, attribute, sizeof(mac_addr), value); | |
} | |
struct nlattr * attr_start(int attribute) { | |
return nla_nest_start(mMsg, attribute); | |
} | |
void attr_end(struct nlattr *attr) { | |
nla_nest_end(mMsg, attr); | |
} | |
int set_iface_id(int ifindex) { | |
return put_u32(NL80211_ATTR_IFINDEX, ifindex); | |
} | |
private: | |
WifiRequest(const WifiRequest&); // hide copy constructor to prevent copies | |
}; | |
class WifiCommand | |
{ | |
protected: | |
hal_info *mInfo; | |
WifiRequest mMsg; | |
Condition mCondition; | |
wifi_request_id mId; | |
interface_info *mIfaceInfo; | |
int mRefs; | |
public: | |
WifiCommand(wifi_handle handle, wifi_request_id id) | |
: mMsg(getHalInfo(handle)->nl80211_family_id), mId(id), mRefs(1) | |
{ | |
mIfaceInfo = NULL; | |
mInfo = getHalInfo(handle); | |
// ALOGD("WifiCommand %p created, mInfo = %p, mIfaceInfo = %p", this, mInfo, mIfaceInfo); | |
} | |
WifiCommand(wifi_interface_handle iface, wifi_request_id id) | |
: mMsg(getHalInfo(iface)->nl80211_family_id, getIfaceInfo(iface)->id), mId(id), mRefs(1) | |
{ | |
mIfaceInfo = getIfaceInfo(iface); | |
mInfo = getHalInfo(iface); | |
// ALOGD("WifiCommand %p created, mInfo = %p, mIfaceInfo = %p", this, mInfo, mIfaceInfo); | |
} | |
virtual ~WifiCommand() { | |
// ALOGD("WifiCommand %p destroyed", this); | |
} | |
wifi_request_id id() { | |
return mId; | |
} | |
virtual void addRef() { | |
int refs = __sync_add_and_fetch(&mRefs, 1); | |
// ALOGD("addRef: WifiCommand %p has %d references", this, refs); | |
} | |
virtual void releaseRef() { | |
int refs = __sync_sub_and_fetch(&mRefs, 1); | |
if (refs == 0) { | |
delete this; | |
} else { | |
// ALOGD("releaseRef: WifiCommand %p has %d references", this, refs); | |
} | |
} | |
virtual int create() { | |
/* by default there is no way to cancel */ | |
ALOGD("WifiCommand %p can't be created", this); | |
return WIFI_ERROR_NOT_SUPPORTED; | |
} | |
virtual int cancel() { | |
/* by default there is no way to cancel */ | |
return WIFI_ERROR_NOT_SUPPORTED; | |
} | |
int requestResponse(); | |
int requestEvent(int cmd); | |
int requestVendorEvent(uint32_t id, int subcmd); | |
int requestResponse(WifiRequest& request); | |
protected: | |
wifi_handle wifiHandle() { | |
return getWifiHandle(mInfo); | |
} | |
wifi_interface_handle ifaceHandle() { | |
return getIfaceHandle(mIfaceInfo); | |
} | |
int familyId() { | |
return mInfo->nl80211_family_id; | |
} | |
int ifaceId() { | |
return mIfaceInfo->id; | |
} | |
/* Override this method to parse reply and dig out data; save it in the object */ | |
virtual int handleResponse(WifiEvent& reply) { | |
ALOGI("skipping a response"); | |
return NL_SKIP; | |
} | |
/* Override this method to parse event and dig out data; save it in the object */ | |
virtual int handleEvent(WifiEvent& event) { | |
ALOGI("skipping an event"); | |
return NL_SKIP; | |
} | |
int registerHandler(int cmd) { | |
return wifi_register_handler(wifiHandle(), cmd, &event_handler, this); | |
} | |
void unregisterHandler(int cmd) { | |
wifi_unregister_handler(wifiHandle(), cmd); | |
} | |
int registerVendorHandler(uint32_t id, int subcmd) { | |
return wifi_register_vendor_handler(wifiHandle(), id, subcmd, &event_handler, this); | |
} | |
void unregisterVendorHandler(uint32_t id, int subcmd) { | |
wifi_unregister_vendor_handler(wifiHandle(), id, subcmd); | |
} | |
private: | |
WifiCommand(const WifiCommand& ); // hide copy constructor to prevent copies | |
/* Event handling */ | |
static int response_handler(struct nl_msg *msg, void *arg); | |
static int event_handler(struct nl_msg *msg, void *arg); | |
/* Other event handlers */ | |
static int valid_handler(struct nl_msg *msg, void *arg); | |
static int ack_handler(struct nl_msg *msg, void *arg); | |
static int finish_handler(struct nl_msg *msg, void *arg); | |
static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg); | |
}; | |
/* nl message processing macros (required to pass C++ type checks) */ | |
#define for_each_attr(pos, nla, rem) \ | |
for (pos = (nlattr *)nla_data(nla), rem = nla_len(nla); \ | |
nla_ok(pos, rem); \ | |
pos = (nlattr *)nla_next(pos, &(rem))) | |