Index: uspace/drv/nic/ar9271/Makefile
===================================================================
--- uspace/drv/nic/ar9271/Makefile	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
+++ uspace/drv/nic/ar9271/Makefile	(revision d7dadcb4162ebe9a54c5014f67b20ba124ddd307)
@@ -34,5 +34,6 @@
 	$(LIBDRV_PREFIX)/libdrv.a \
 	$(LIBNIC_PREFIX)/libnic.a \
-	$(LIBIEEE80211_PREFIX)/libieee80211.a
+	$(LIBIEEE80211_PREFIX)/libieee80211.a \
+	$(LIBCRYPTO_PREFIX)/libcrypto.a
 	
 EXTRA_CFLAGS += \
@@ -43,4 +44,5 @@
 	-I$(LIBNIC_PREFIX)/include \
 	-I$(LIBIEEE80211_PREFIX)/include \
+	-I$(LIBCRYPTO_PREFIX)
 	
 BINARY = ar9271
Index: uspace/drv/nic/ar9271/ar9271.c
===================================================================
--- uspace/drv/nic/ar9271/ar9271.c	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
+++ uspace/drv/nic/ar9271/ar9271.c	(revision d7dadcb4162ebe9a54c5014f67b20ba124ddd307)
@@ -105,4 +105,7 @@
 static int ar9271_ieee80211_set_freq(ieee80211_dev_t *ieee80211_dev,
 	uint16_t freq);
+static int ar9271_ieee80211_bssid_change(ieee80211_dev_t *ieee80211_dev);
+static int ar9271_ieee80211_key_config(ieee80211_dev_t *ieee80211_dev,
+	ieee80211_key_config_t *key_conf, bool insert);
 
 static driver_ops_t ar9271_driver_ops = {
@@ -118,5 +121,7 @@
 	.start = ar9271_ieee80211_start,
 	.tx_handler = ar9271_ieee80211_tx_handler,
-	.set_freq = ar9271_ieee80211_set_freq
+	.set_freq = ar9271_ieee80211_set_freq,
+	.bssid_change = ar9271_ieee80211_bssid_change,
+	.key_config = ar9271_ieee80211_key_config
 };
 
@@ -186,6 +191,6 @@
  *
  */
-static int ar9271_on_multicast_mode_change(nic_t *nic, nic_multicast_mode_t mode,
-    const nic_address_t *addr, size_t addr_cnt)
+static int ar9271_on_multicast_mode_change(nic_t *nic, 
+	nic_multicast_mode_t mode, const nic_address_t *addr, size_t addr_cnt)
 {
 	/*
@@ -249,5 +254,6 @@
  *
  */
-static int ar9271_on_broadcast_mode_change(nic_t *nic, nic_broadcast_mode_t mode)
+static int ar9271_on_broadcast_mode_change(nic_t *nic, 
+	nic_broadcast_mode_t mode)
 {
 	/*
@@ -271,6 +277,13 @@
 }
 
+static bool ar9271_rx_status_error(uint8_t status)
+{
+	return (status & AR9271_RX_ERROR_PHY) || (status & AR9271_RX_ERROR_CRC);
+}
+
 static int ar9271_data_polling(void *arg)
 {
+	assert(arg);
+	
 	ar9271_t *ar9271 = (ar9271_t *) arg;
 	
@@ -282,23 +295,41 @@
 		if(htc_read_data_message(ar9271->htc_device, 
 			buffer, buffer_size, &transferred_size) == EOK) {
-			ath_usb_data_header_t *data_header = 
-				(ath_usb_data_header_t *) buffer;
-
-			/* Invalid packet. */
-			if(data_header->tag != uint16_t_le2host(RX_TAG)) {
-				continue;
-			}
-			
 			size_t strip_length = 
 				sizeof(ath_usb_data_header_t) +
 				sizeof(htc_frame_header_t) + 
-				HTC_RX_HEADER_LENGTH;
+				sizeof(htc_rx_status_t);
 			
-			/* TODO: RX header inspection. */
+			if(transferred_size < strip_length)
+				continue;
+
+			ath_usb_data_header_t *data_header = 
+				(ath_usb_data_header_t *) buffer;
+
+			/* Invalid packet. */
+			if(data_header->tag != uint16_t_le2host(RX_TAG))
+				continue;
+			
+			htc_rx_status_t *rx_status =
+				(htc_rx_status_t *) ((void *) buffer +
+				sizeof(ath_usb_data_header_t) +
+				sizeof(htc_frame_header_t));
+			
+			uint16_t data_length =
+				uint16_t_be2host(rx_status->data_length);
+			
+			int16_t payload_length = 
+				transferred_size - strip_length;
+			
+			if(payload_length - data_length < 0)
+				continue;
+			
+			if(ar9271_rx_status_error(rx_status->status))
+				continue;
+			
 			void *strip_buffer = buffer + strip_length;
-			
+
 			ieee80211_rx_handler(ar9271->ieee80211_dev,
 				strip_buffer,
-				transferred_size - strip_length);
+				payload_length);
 		}
 	}
@@ -316,5 +347,9 @@
 	uint16_t freq)
 {
+	assert(ieee80211_dev);
+	
 	ar9271_t *ar9271 = (ar9271_t *) ieee80211_get_specific(ieee80211_dev);
+	
+	//hw_wakeup(ar9271);
 	
 	wmi_send_command(ar9271->htc_device, WMI_DISABLE_INTR, NULL, 0, NULL);
@@ -344,7 +379,156 @@
 }
 
+static int ar9271_ieee80211_bssid_change(ieee80211_dev_t *ieee80211_dev)
+{
+	assert(ieee80211_dev);
+	
+	ar9271_t *ar9271 = (ar9271_t *) ieee80211_get_specific(ieee80211_dev);
+
+	/* Check if we are connected or disconnected. */
+	if(ieee80211_is_connected(ieee80211_dev)) {
+		nic_address_t bssid;
+		ieee80211_query_bssid(ieee80211_dev, &bssid);
+
+		htc_sta_msg_t sta_msg;
+		memset(&sta_msg, 0, sizeof(htc_sta_msg_t));
+		sta_msg.is_vif_sta = 0;
+		sta_msg.max_ampdu = 
+			host2uint16_t_be(1 << IEEE80211_MAX_AMPDU_FACTOR);
+		sta_msg.sta_index = 1;
+		sta_msg.vif_index = 0;
+		memcpy(&sta_msg.addr, bssid.address, ETH_ADDR);
+
+		wmi_send_command(ar9271->htc_device, WMI_NODE_CREATE, 
+			(uint8_t *) &sta_msg, sizeof(sta_msg), NULL);
+
+		htc_rate_msg_t rate_msg;
+		memset(&rate_msg, 0, sizeof(htc_rate_msg_t));
+		rate_msg.sta_index = 1;
+		rate_msg.is_new = 1;
+		rate_msg.legacy_rates_count = 
+			ARRAY_SIZE(ieee80211bg_data_rates);
+		memcpy(&rate_msg.legacy_rates, 
+			ieee80211bg_data_rates, 
+			ARRAY_SIZE(ieee80211bg_data_rates));
+
+		wmi_send_command(ar9271->htc_device, WMI_RC_RATE_UPDATE, 
+			(uint8_t *) &rate_msg, sizeof(rate_msg), NULL);
+
+		hw_set_rx_filter(ar9271, true);
+	} else {
+		uint8_t station_id = 1;
+		wmi_send_command(ar9271->htc_device, WMI_NODE_REMOVE,
+			&station_id, sizeof(station_id), NULL);
+		
+		hw_set_rx_filter(ar9271, false);
+	}
+	
+	hw_set_bssid(ar9271);
+	
+	return EOK;
+}
+
+static int ar9271_ieee80211_key_config(ieee80211_dev_t *ieee80211_dev,
+	ieee80211_key_config_t *key_conf, bool insert)
+{
+	assert(ieee80211_dev);
+	assert(key_conf);
+	
+	ar9271_t *ar9271 = (ar9271_t *) ieee80211_get_specific(ieee80211_dev);
+	
+	uint32_t key[5];
+	uint32_t key_type;
+	uint32_t reg_ptr;
+	void *data_start;
+	
+	if(insert) {
+		nic_address_t bssid;
+		ieee80211_query_bssid(ieee80211_dev, &bssid);
+		
+		switch(key_conf->suite) {
+			case IEEE80211_SECURITY_SUITE_WEP40:
+				key_type = AR9271_KEY_TABLE_TYPE_WEP40;
+				break;
+			case IEEE80211_SECURITY_SUITE_WEP104:
+				key_type = AR9271_KEY_TABLE_TYPE_WEP104;
+				break;
+			case IEEE80211_SECURITY_SUITE_TKIP:
+				key_type = AR9271_KEY_TABLE_TYPE_TKIP;
+				break;
+			case IEEE80211_SECURITY_SUITE_CCMP:
+				key_type = AR9271_KEY_TABLE_TYPE_CCMP;
+				break;
+			default:
+				key_type = -1;
+		}
+		
+		if(key_conf->flags & IEEE80211_KEY_FLAG_TYPE_PAIRWISE) {
+			reg_ptr = AR9271_KEY_TABLE_STA;
+		} else {
+			reg_ptr = AR9271_KEY_TABLE_GRP;
+		}
+		
+		if(key_conf->suite == IEEE80211_SECURITY_SUITE_TKIP) {
+			// TODO
+		} else {
+			data_start = (void *) key_conf->data;
+			
+			key[0] = uint32_t_le2host(
+				*((uint32_t *) data_start));
+			key[1] = uint16_t_le2host(
+				*((uint16_t *) (data_start + 4)));
+			key[2] = uint32_t_le2host(
+				*((uint32_t *) (data_start + 6)));
+			key[3] = uint16_t_le2host(
+				*((uint16_t *) (data_start + 10)));
+			key[4] = uint32_t_le2host(
+				*((uint32_t *) (data_start + 12)));
+			
+			if(key_conf->suite == IEEE80211_SECURITY_SUITE_WEP40 ||
+			   key_conf->suite == IEEE80211_SECURITY_SUITE_WEP104) {
+				key[4] &= 0xFF;
+			}
+			
+			wmi_reg_write(ar9271->htc_device, reg_ptr + 0, key[0]);
+			wmi_reg_write(ar9271->htc_device, reg_ptr + 4, key[1]);
+			wmi_reg_write(ar9271->htc_device, reg_ptr + 8, key[2]);
+			wmi_reg_write(ar9271->htc_device, reg_ptr + 12, key[3]);
+			wmi_reg_write(ar9271->htc_device, reg_ptr + 16, key[4]);
+			wmi_reg_write(ar9271->htc_device, reg_ptr + 20, 
+				key_type);
+		}
+		
+		uint32_t macL, macH;
+		if(key_conf->flags & IEEE80211_KEY_FLAG_TYPE_PAIRWISE) {
+			data_start = (void *) bssid.address;
+			macL = uint32_t_le2host(*((uint32_t *) data_start));
+			macH = uint16_t_le2host(*((uint16_t *) 
+				(data_start + 4)));
+		} else {
+			macL = macH = 0;
+		}
+		
+		macL >>= 1;
+		macL |= (macH & 1) << 31;
+		macH >>= 1;
+		macH |= 0x8000;
+		
+		wmi_reg_write(ar9271->htc_device, reg_ptr + 24, macL);
+		wmi_reg_write(ar9271->htc_device, reg_ptr + 28, macH);
+		
+		if(key_conf->flags & IEEE80211_KEY_FLAG_TYPE_GROUP)
+			ieee80211_setup_key_confirm(ieee80211_dev, true);
+	} else {
+		// TODO
+	}
+	
+	return EOK;
+}
+
 static int ar9271_ieee80211_tx_handler(ieee80211_dev_t *ieee80211_dev,
 	void *buffer, size_t buffer_size)
 {
+	assert(ieee80211_dev);
+	
 	size_t complete_size, offset;
 	void *complete_buffer;
@@ -355,7 +539,48 @@
 	uint16_t frame_ctrl = *((uint16_t *) buffer);
 	if(ieee80211_is_data_frame(frame_ctrl)) {
-		offset = sizeof(htc_frame_header_t);
+		offset = sizeof(htc_tx_data_header_t) +
+			sizeof(htc_frame_header_t);
 		complete_size = buffer_size + offset;
 		complete_buffer = malloc(complete_size);
+		memset(complete_buffer, 0, complete_size);
+		
+		/* 
+		 * Because we handle just station mode yet, node ID and VIF ID
+		 * are fixed.
+		 */
+		htc_tx_data_header_t *data_header =
+			(htc_tx_data_header_t *) 
+			(complete_buffer + sizeof(htc_frame_header_t));
+		/* TODO: Distinguish data type. */
+		data_header->data_type = HTC_DATA_NORMAL;
+		data_header->node_idx = 1;
+		data_header->vif_idx = 0;
+		/* TODO: There I should probably handle slot number. */
+		data_header->cookie = 0;
+		
+		if(ieee80211_query_using_key(ieee80211_dev)) {
+			data_header->keyix = AR9271_STA_KEY_INDEX;
+			int sec_suite = 
+				ieee80211_get_security_suite(ieee80211_dev);
+			switch(sec_suite) {
+				case IEEE80211_SECURITY_SUITE_WEP40:
+				case IEEE80211_SECURITY_SUITE_WEP104:
+					data_header->key_type =
+						AR9271_KEY_TYPE_WEP;
+					break;
+				case IEEE80211_SECURITY_SUITE_TKIP:
+					data_header->key_type =
+						AR9271_KEY_TYPE_TKIP;
+					break;
+				case IEEE80211_SECURITY_SUITE_CCMP:
+					data_header->key_type =
+						AR9271_KEY_TYPE_AES;
+					break;
+			}
+		} else {
+			data_header->key_type = 0;
+			data_header->keyix = 0xFF;
+		}
+		
 		endpoint = ar9271->htc_device->endpoints.data_be_endpoint;
 	} else {
@@ -366,7 +591,15 @@
 		memset(complete_buffer, 0, complete_size);
 		
+		/* 
+		 * Because we handle just station mode yet, node ID and VIF ID
+		 * are fixed.
+		 */
 		htc_tx_management_header_t *mgmt_header =
 			(htc_tx_management_header_t *) 
 			(complete_buffer + sizeof(htc_frame_header_t));
+		mgmt_header->node_idx = 0;
+		mgmt_header->vif_idx = 0;
+		/* TODO: There I should probably handle slot number. */
+		mgmt_header->cookie = 0;
 		mgmt_header->keyix = 0xFF;
 		
@@ -387,4 +620,6 @@
 static int ar9271_ieee80211_start(ieee80211_dev_t *ieee80211_dev)
 {
+	assert(ieee80211_dev);
+	
 	ar9271_t *ar9271 = (ar9271_t *) ieee80211_get_specific(ieee80211_dev);
 	
@@ -434,4 +669,7 @@
 	
 	ar9271->starting_up = false;
+	ieee80211_set_ready(ieee80211_dev, true);
+	
+	usb_log_info("Device fully initialized.\n");
 	
 	return EOK;
Index: uspace/drv/nic/ar9271/ar9271.h
===================================================================
--- uspace/drv/nic/ar9271/ar9271.h	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
+++ uspace/drv/nic/ar9271/ar9271.h	(revision d7dadcb4162ebe9a54c5014f67b20ba124ddd307)
@@ -46,4 +46,22 @@
 #define AR9271_LED_PIN 15
 
+/** Nominal value for AR9271 noise floor calibration. */
+#define AR9271_CALIB_NOMINAL_VALUE_2GHZ -118
+
+/** RX errors values. */
+#define AR9271_RX_ERROR_CRC 0x01
+#define AR9271_RX_ERROR_PHY 0x02
+
+/** Key index used for device in station mode. */
+#define AR9271_STA_KEY_INDEX 4
+
+/* HW encryption key indicator. */
+enum ath9k_key_type {
+	AR9271_KEY_TYPE_CLEAR,
+	AR9271_KEY_TYPE_WEP,
+	AR9271_KEY_TYPE_AES,
+	AR9271_KEY_TYPE_TKIP,
+};
+
 /** AR9271 Registers */
 typedef enum {
@@ -75,5 +93,5 @@
 	AR9271_GPIO_OUT_MUX_AS_OUT = 0x0,	/**< GPIO set mux as output */
     
-	/* Wakeup related registers */
+	/* RTC related registers */
 	AR9271_RTC_RC = 0x7000,
 	AR9271_RTC_RC_MAC_WARM = 0x00000001,
@@ -86,4 +104,6 @@
 	AR9271_RTC_STATUS_SHUTDOWN = 0x00000001,
 	AR9271_RTC_STATUS_ON = 0x00000002,
+	AR9271_RTC_SLEEP_CLOCK = 0x7048,
+	AR9271_RTC_SLEEP_CLOCK_FORCE_DERIVED = 0x2,
 	AR9271_RTC_FORCE_WAKE = 0x704C,
 	AR9271_RTC_FORCE_WAKE_ENABLE = 0x00000001,
@@ -93,10 +113,13 @@
 	AR9271_STATION_ID0 = 0x8000,	/**< STA Address Lower 32 Bits */
 	AR9271_STATION_ID1 = 0x8004,	/**< STA Address Upper 16 Bits */
-	AR9271_BSSID0 = 0x8008,			/**< BSSID Lower 32 Bits */
-	AR9271_BSSID1 = 0x800C,			/**< BSSID Upper 16 Bits */
-	AR9271_BSSID_MASK0 = 0x80E0,		/**< BSSID Mask Lower 32 Bits */
-	AR9271_BSSID_MASK1 = 0x80E4,		/**< BSSID Mask Upper 16 Bits */
+	AR9271_BSSID0 = 0x8008,		/**< BSSID Lower 32 Bits */
+	AR9271_BSSID1 = 0x800C,		/**< BSSID Upper 16 Bits */
+	AR9271_BSSID_MASK0 = 0x80E0,	/**< BSSID Mask Lower 32 Bits */
+	AR9271_BSSID_MASK1 = 0x80E4,	/**< BSSID Mask Upper 16 Bits */
 	AR9271_STATION_ID1_MASK = 0x0000FFFF,
 	AR9271_STATION_ID1_POWER_SAVING = 0x00040000,
+	AR9271_MULTICAST_FILTER1 = 0x8040,
+	AR9271_MULTICAST_FILTER2 = 0x8044,	
+	AR9271_DIAG = 0x8048,
 		
 	/* RX filtering register */
@@ -110,7 +133,13 @@
 	AR9271_RX_FILTER_PROBEREQ = 0x00000080,
 	AR9271_RX_FILTER_MYBEACON = 0x00000200,
-	AR9271_MULTICAST_FILTER1 = 0x8040,
-	AR9271_MULTICAST_FILTER2 = 0x8044,	
-	AR9271_DIAG = 0x8048,
+	AR9271_RX_FILTER_MCAST_BCAST_ALL = 0x00008000,
+		
+	/* Key related registers */
+	AR9271_KEY_TABLE_GRP = 0x8820,
+	AR9271_KEY_TABLE_STA = 0x8880,
+	AR9271_KEY_TABLE_TYPE_WEP40 = 0x0,
+	AR9271_KEY_TABLE_TYPE_WEP104 = 0x1,
+	AR9271_KEY_TABLE_TYPE_TKIP = 0x4,
+	AR9271_KEY_TABLE_TYPE_CCMP = 0x6,
 		
 	/* Physical layer registers */
@@ -118,4 +147,5 @@
 	AR9271_ADC_CONTROL = 0x982C,
 	AR9271_AGC_CONTROL = 0x9860,
+	AR9271_PHY_CAL = 0x9864,
 	AR9271_PHY_SYNTH_CONTROL = 0x9874, 
 	AR9271_PHY_SPECTRAL_SCAN = 0x9910,
Index: uspace/drv/nic/ar9271/ath_usb.h
===================================================================
--- uspace/drv/nic/ar9271/ath_usb.h	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
+++ uspace/drv/nic/ar9271/ath_usb.h	(revision d7dadcb4162ebe9a54c5014f67b20ba124ddd307)
@@ -57,5 +57,5 @@
 typedef struct {
 	uint16_t length;		/**< Little Endian value! */
-	uint16_t tag;		/**< Little Endian value! */
+	uint16_t tag;			/**< Little Endian value! */
 } ath_usb_data_header_t;
 
Index: uspace/drv/nic/ar9271/htc.c
===================================================================
--- uspace/drv/nic/ar9271/htc.c	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
+++ uspace/drv/nic/ar9271/htc.c	(revision d7dadcb4162ebe9a54c5014f67b20ba124ddd307)
@@ -75,5 +75,8 @@
 	
 	nic_address_t addr;
-	nic_t *nic = nic_get_from_ddf_dev(ieee80211_get_ddf_dev(htc_device->ieee80211_dev));
+	nic_t *nic = 
+		nic_get_from_ddf_dev(
+			ieee80211_get_ddf_dev(htc_device->ieee80211_dev)
+		);
 	nic_query_address(nic, &addr);
 	
@@ -128,6 +131,4 @@
 	wmi_reg_write(htc_device, AR9271_STATION_ID1, id1);
 	
-	/* TODO: Set BSSID mask for AP mode. */
-	
 	return EOK;
 }
Index: uspace/drv/nic/ar9271/htc.h
===================================================================
--- uspace/drv/nic/ar9271/htc.h	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
+++ uspace/drv/nic/ar9271/htc.h	(revision d7dadcb4162ebe9a54c5014f67b20ba124ddd307)
@@ -45,8 +45,8 @@
 
 #define HTC_RTS_THRESHOLD 2304
-#define HTC_RX_HEADER_LENGTH 40
-
-/**
- * HTC message IDs
+#define HTC_RATES_MAX_LENGTH 30
+
+/**
+ * HTC message IDs.
  */
 typedef enum {
@@ -59,5 +59,5 @@
 
 /**
- * HTC response message status codes
+ * HTC response message status codes.
  */
 typedef enum {
@@ -70,5 +70,5 @@
 
 /**
- * HTC operating mode definition
+ * HTC operating mode definition.
  */
 typedef enum {
@@ -80,5 +80,15 @@
 
 /**
- * HTC endpoint numbers
+ * HTC data type indicator.
+ */
+typedef enum {
+	HTC_DATA_AMPDU = 1,
+	HTC_DATA_NORMAL = 2,
+	HTC_DATA_BEACON = 3,
+	HTC_DATA_MGMT = 4
+} htc_data_type_t;
+
+/**
+ * HTC endpoint numbers.
  */
 typedef struct {
@@ -96,5 +106,5 @@
 
 /**
- * HTC device data
+ * HTC device data.
  */
 typedef struct {
@@ -119,5 +129,5 @@
 
 /** 
- * HTC frame header structure 
+ * HTC frame header structure.
  */
 typedef struct {
@@ -126,10 +136,8 @@
 	uint16_t  payload_length;	/**< Big Endian value! */
 	uint8_t   control_bytes[4];
-    
-	/* Message payload starts after the header. */
 } __attribute__((packed)) htc_frame_header_t;
 
 /** 
- * HTC management TX frame header structure 
+ * HTC management TX frame header structure.
  */
 typedef struct {
@@ -145,5 +153,20 @@
 
 /** 
- * HTC ready message structure 
+ * HTC data TX frame header structure.
+ */
+typedef struct {
+	uint8_t data_type;
+	uint8_t node_idx;
+	uint8_t vif_idx;
+	uint8_t tidno;
+	uint32_t flags;			/**< Big Endian value! */
+	uint8_t key_type;
+	uint8_t keyix;
+	uint8_t cookie;
+	uint8_t pad;
+} __attribute__((packed)) htc_tx_data_header_t;
+
+/** 
+ * HTC ready message structure.
  */
 typedef struct {
@@ -157,5 +180,5 @@
 
 /** 
- * HTC service message structure 
+ * HTC service message structure.
  */
 typedef struct {
@@ -171,5 +194,5 @@
 
 /** 
- * HTC service response message structure 
+ * HTC service response message structure.
  */
 typedef struct {
@@ -184,5 +207,5 @@
 
 /**
- * HTC credits config message structure
+ * HTC credits config message structure.
  */
 typedef struct {
@@ -193,5 +216,5 @@
 
 /**
- * HTC new virtual interface message
+ * HTC new virtual interface message.
  */
 typedef struct {
@@ -205,5 +228,5 @@
 
 /**
- * HTC new station message
+ * HTC new station message.
  */
 typedef struct {
@@ -231,4 +254,38 @@
 	uint8_t pad;
 } __attribute__((packed)) htc_cap_msg_t;
+
+typedef struct {
+	uint8_t sta_index;
+	uint8_t is_new;
+	uint32_t cap_flags;	/**< Big Endian value! */
+	uint8_t legacy_rates_count;
+	uint8_t legacy_rates[HTC_RATES_MAX_LENGTH];
+	uint16_t pad;
+} htc_rate_msg_t;
+
+/**
+ * HTC RX status structure used in incoming HTC data messages.
+ */
+typedef struct {
+	uint64_t timestamp;	/**< Big Endian value! */
+	uint16_t data_length;	/**< Big Endian value! */
+	uint8_t status;
+	uint8_t phy_err;
+	int8_t rssi;
+	int8_t rssi_ctl[3];
+	int8_t rssi_ext[3];
+	uint8_t keyix;
+	uint8_t rate;
+	uint8_t antenna;
+	uint8_t more;
+	uint8_t is_aggr;
+	uint8_t more_aggr;
+	uint8_t num_delims;
+	uint8_t flags;
+	uint8_t dummy;
+	uint32_t evm0;		/**< Big Endian value! */
+	uint32_t evm1;		/**< Big Endian value! */
+	uint32_t evm2;		/**< Big Endian value! */
+} htc_rx_status_t;
 
 /**
Index: uspace/drv/nic/ar9271/hw.c
===================================================================
--- uspace/drv/nic/ar9271/hw.c	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
+++ uspace/drv/nic/ar9271/hw.c	(revision d7dadcb4162ebe9a54c5014f67b20ba124ddd307)
@@ -43,6 +43,5 @@
 
 /**
- * Try to wait for register value repeatedly until timeout defined by device 
- * is reached.
+ * Try to wait for register value repeatedly until timeout is reached.
  * 
  * @param ar9271 Device structure.
@@ -264,4 +263,12 @@
 }
 
+static int hw_activate_phy(ar9271_t *ar9271)
+{
+	wmi_reg_write(ar9271->htc_device, AR9271_PHY_ACTIVE, 1);
+	udelay(1000);
+	
+	return EOK;
+}
+
 static int hw_set_operating_mode(ar9271_t *ar9271, 
 	ieee80211_operating_mode_t op_mode)
@@ -305,4 +312,26 @@
 static int hw_noise_floor_calibration(ar9271_t *ar9271)
 {
+	uint32_t value;
+	wmi_reg_read(ar9271->htc_device, AR9271_PHY_CAL, &value);
+	value &= 0xFFFFFE00;
+	value |= (((uint32_t) AR9271_CALIB_NOMINAL_VALUE_2GHZ << 1) & 0x1FF);
+	wmi_reg_write(ar9271->htc_device, AR9271_PHY_CAL, value);
+	
+	wmi_reg_clear_bit(ar9271->htc_device, AR9271_AGC_CONTROL, 
+		AR9271_AGC_CONTROL_NF_CALIB_EN);
+	
+	wmi_reg_clear_bit(ar9271->htc_device, AR9271_AGC_CONTROL, 
+		AR9271_AGC_CONTROL_NF_NOT_UPDATE);
+	
+	wmi_reg_set_bit(ar9271->htc_device, AR9271_AGC_CONTROL, 
+		AR9271_AGC_CONTROL_NF_CALIB);
+	
+	int rc = hw_read_wait(ar9271, AR9271_AGC_CONTROL, 
+		AR9271_AGC_CONTROL_NF_CALIB, 0);
+	if(rc != EOK) {
+		usb_log_error("Failed to wait for NF calibration.\n");
+		return rc;
+	}
+	
 	wmi_reg_set_bit(ar9271->htc_device, AR9271_AGC_CONTROL, 
 		AR9271_AGC_CONTROL_NF_CALIB_EN);
@@ -348,4 +377,47 @@
 }
 
+int hw_wakeup(ar9271_t *ar9271)
+{
+	int rc;
+	
+	uint32_t rtc_status;
+	wmi_reg_read(ar9271->htc_device, AR9271_RTC_STATUS, &rtc_status);
+	if((rtc_status & AR9271_RTC_STATUS_MASK) == AR9271_RTC_STATUS_SHUTDOWN) {
+		rc = hw_reset_power_on(ar9271);
+		if(rc != EOK) {
+			usb_log_info("Failed to HW reset power on.\n");
+			return rc;
+		}
+
+		rc = hw_set_reset(ar9271, false);
+		if(rc != EOK) {
+			usb_log_info("Failed to HW warm reset.\n");
+			return rc;
+		}
+	}
+	
+	wmi_reg_set_bit(ar9271->htc_device, AR9271_RTC_FORCE_WAKE,
+		AR9271_RTC_FORCE_WAKE_ENABLE);
+	
+	size_t i;
+	for(i = 0; i < HW_WAIT_LOOPS; i++) {
+		wmi_reg_read(ar9271->htc_device, AR9271_RTC_STATUS, 
+			&rtc_status);
+		if((rtc_status & AR9271_RTC_STATUS_MASK) == 
+			AR9271_RTC_STATUS_ON) {
+			break;
+		}
+		wmi_reg_set_bit(ar9271->htc_device, AR9271_RTC_FORCE_WAKE,
+			AR9271_RTC_FORCE_WAKE_ENABLE);
+		udelay(50);
+	}	
+	
+	if(i == HW_WAIT_LOOPS) {
+		return EINVAL;
+	} else {
+		return EOK;
+	}
+}
+
 int hw_freq_switch(ar9271_t *ar9271, uint16_t freq)
 {
@@ -361,4 +433,10 @@
 	if(rc != EOK) {
 		usb_log_error("Failed to HW set frequency.\n");
+		return rc;
+	}
+	
+	rc = hw_activate_phy(ar9271);
+	if(rc != EOK) {
+		usb_log_error("Failed to activate physical layer.\n");
 		return rc;
 	}
@@ -376,14 +454,40 @@
 }
 
-static int hw_set_rx_filter(ar9271_t *ar9271)
+int hw_set_rx_filter(ar9271_t *ar9271, bool assoc)
 {
 	uint32_t filter_bits;
 	
-	/* TODO: Do proper filtering here. */
+	uint32_t additional_bits = 0;
+	
+	if(assoc) {
+		additional_bits |= AR9271_RX_FILTER_MYBEACON;
+	} else {
+		additional_bits |= AR9271_RX_FILTER_BEACON;
+	}
 	
 	filter_bits = AR9271_RX_FILTER_UNI | AR9271_RX_FILTER_MULTI | 
-		AR9271_RX_FILTER_BROAD | AR9271_RX_FILTER_BEACON;
+		AR9271_RX_FILTER_BROAD | additional_bits;
 	
 	wmi_reg_write(ar9271->htc_device, AR9271_RX_FILTER, filter_bits);
+	
+	return EOK;
+}
+
+int hw_set_bssid(ar9271_t *ar9271)
+{
+	ieee80211_dev_t *ieee80211_dev = ar9271->ieee80211_dev;
+	
+	nic_address_t bssid;
+	ieee80211_query_bssid(ieee80211_dev, &bssid);
+	
+	uint32_t *first_4bytes = (uint32_t *) &bssid.address;
+	uint16_t *last_2bytes = (uint16_t *) &bssid.address[4];
+	
+	wmi_reg_write(ar9271->htc_device, AR9271_BSSID0, 
+		uint32_t_le2host(*first_4bytes));
+	
+	wmi_reg_write(ar9271->htc_device, AR9271_BSSID1, 
+		uint16_t_le2host(*last_2bytes) | 
+		((ieee80211_get_aid(ieee80211_dev) & 0x3FFF) << 16));
 	
 	return EOK;
@@ -395,5 +499,5 @@
 		AR9271_COMMAND_RX_ENABLE);
 	
-	int rc = hw_set_rx_filter(ar9271);
+	int rc = hw_set_rx_filter(ar9271, false);
 	if(rc != EOK) {
 		usb_log_error("Failed to set RX filtering.\n");
@@ -410,12 +514,4 @@
 }
 
-static int hw_activate_phy(ar9271_t *ar9271)
-{
-	wmi_reg_write(ar9271->htc_device, AR9271_PHY_ACTIVE, 1);
-	udelay(1000);
-	
-	return EOK;
-}
-
 static int hw_init_pll(ar9271_t *ar9271)
 {
@@ -423,13 +519,17 @@
 	
 	/* Some magic here (set for 2GHz channels). But VERY important :-) */
-	pll = (0x5 << 10) & 0x00003C00;
-	pll |= 0x2C & 0x000003FF;
+	pll = (0x5 << 10) | 0x2C;
 	
 	wmi_reg_write(ar9271->htc_device, AR9271_RTC_PLL_CONTROL, pll);
 	
-	return EOK;
-}
-
-static int hw_set_init_values(ar9271_t *ar9271)
+	wmi_reg_write(ar9271->htc_device, AR9271_RTC_SLEEP_CLOCK,
+		AR9271_RTC_SLEEP_CLOCK_FORCE_DERIVED);
+	wmi_reg_set_bit(ar9271->htc_device, AR9271_RTC_FORCE_WAKE,
+		AR9271_RTC_FORCE_WAKE_ENABLE);
+	
+	return EOK;
+}
+
+static void hw_set_init_values(ar9271_t *ar9271)
 {
 	uint32_t reg_offset, reg_value;
@@ -458,6 +558,4 @@
 		wmi_reg_write(ar9271->htc_device, reg_offset, reg_value);
 	}
-	
-	return EOK;
 }
 
@@ -533,9 +631,5 @@
 	}
 	
-	rc = hw_set_init_values(ar9271);
-	if(rc != EOK) {
-		usb_log_error("Failed to set device init values.\n");
-		return rc;
-	}
+	hw_set_init_values(ar9271);
 	
 	/* Set physical layer mode. */
@@ -586,6 +680,4 @@
 	/* Byteswap TX and RX data buffer words. */
 	wmi_reg_write(ar9271->htc_device, AR9271_CONFIG, 0xA);
-	
-	usb_log_info("HW reset done.\n");
 	
 	return EOK;
Index: uspace/drv/nic/ar9271/hw.h
===================================================================
--- uspace/drv/nic/ar9271/hw.h	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
+++ uspace/drv/nic/ar9271/hw.h	(revision d7dadcb4162ebe9a54c5014f67b20ba124ddd307)
@@ -45,4 +45,7 @@
 extern int hw_rx_init(ar9271_t *ar9271);
 extern int hw_reset(ar9271_t *ar9271);
+extern int hw_wakeup(ar9271_t *ar9271);
+extern int hw_set_bssid(ar9271_t *ar9271);
+extern int hw_set_rx_filter(ar9271_t *ar9271, bool assoc);
 
 #endif	/* ATHEROS_HW_H */
Index: uspace/drv/nic/ar9271/wmi.c
===================================================================
--- uspace/drv/nic/ar9271/wmi.c	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
+++ uspace/drv/nic/ar9271/wmi.c	(revision d7dadcb4162ebe9a54c5014f67b20ba124ddd307)
@@ -231,5 +231,8 @@
 	size_t buffer_size = header_size + command_length;
 	void *buffer = malloc(buffer_size);
-	memcpy(buffer+header_size, command_buffer, command_length);
+	
+	if(command_buffer != NULL) {
+		memcpy(buffer+header_size, command_buffer, command_length);
+	}
 	
 	/* Set up WMI header */
@@ -261,12 +264,27 @@
 	
 	/* Read response. */
-	rc = htc_read_control_message(htc_device, response_buffer, 
-		response_buffer_size, NULL);
-	if(rc != EOK) {
-		free(buffer);
-		usb_log_error("Failed to receive WMI message response. "
-		    "Error: %d\n", rc);
-		return rc;
-	}
+	/* TODO: Ignoring WMI management RX messages ~ TX statuses etc. */
+	uint16_t cmd_id;
+	do {
+		rc = htc_read_control_message(htc_device, response_buffer, 
+			response_buffer_size, NULL);
+		if(rc != EOK) {
+			free(buffer);
+			usb_log_error("Failed to receive WMI message response. "
+			    "Error: %d\n", rc);
+			return rc;
+		}
+		
+		if(response_buffer_size < sizeof(htc_frame_header_t) + 
+			sizeof(wmi_command_header_t)) {
+			free(buffer);
+			usb_log_error("Corrupted response received.\n");
+			return EINVAL;
+		}
+		
+		wmi_command_header_t *wmi_hdr = (wmi_command_header_t *) 
+			((void*) response_buffer + sizeof(htc_frame_header_t));
+		cmd_id = uint16_t_be2host(wmi_hdr->command_id);
+	} while(cmd_id & WMI_MGMT_CMD_MASK);
 	
 	if(clean_resp_buffer) {
Index: uspace/drv/nic/ar9271/wmi.h
===================================================================
--- uspace/drv/nic/ar9271/wmi.h	(revision 59fa7ab26f7b4336f753dcd52b89d6cac0dfca97)
+++ uspace/drv/nic/ar9271/wmi.h	(revision d7dadcb4162ebe9a54c5014f67b20ba124ddd307)
@@ -42,4 +42,6 @@
 #define WMI_SERVICE_GROUP 1
 #define CREATE_SERVICE_ID(group, i) (int) (((int) group << 8) | (int) (i))
+
+#define WMI_MGMT_CMD_MASK 0x1000
 
 /**
@@ -117,6 +119,6 @@
 extern int wmi_reg_write(htc_device_t *htc_device, uint32_t reg_offset, 
 	uint32_t val);
-extern int wmi_reg_set_clear_bit(htc_device_t *htc_device, uint32_t reg_offset, 
-	uint32_t set_bit, uint32_t clear_bit);
+extern int wmi_reg_set_clear_bit(htc_device_t *htc_device, 
+	uint32_t reg_offset, uint32_t set_bit, uint32_t clear_bit);
 extern int wmi_reg_set_bit(htc_device_t *htc_device, uint32_t reg_offset, 
 	uint32_t set_bit);
