aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDaniel C Halperin <daniel.c.halperin@intel.com>2009-11-13 14:56:33 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-11-18 17:09:06 -0500
commit47ff65c48748086a5e9cde6032451691a28ab19f (patch)
treed1b2923d7e79deef4355918de75b19ed2f8b750f /drivers
parente43ab94d2ea01a74e60c3423334687c2156c39b2 (diff)
iwlwifi: fix bugs in beacon configuration
When sending beacon commands to the uCode, we must inform it of the offset in the beacon frame of the TIM Element so it can transmit packets from the correct queue. This functionality is implemented in iwl_set_beacon_tim(). Fix a bug setting the rate_n_flags for the beacon packet. First, it should not use the station table's rate (it's a management frame), and second it needs to properly configure the TX antennas. Finally, also, clean up and comment relevant functions. Signed-off-by: Daniel C Halperin <daniel.c.halperin@intel.com> Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c83
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c1
2 files changed, 63 insertions, 21 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index f586e7e83131..29f3b73c7560 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -310,7 +310,7 @@ static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame)
310 list_add(&frame->list, &priv->free_frames); 310 list_add(&frame->list, &priv->free_frames);
311} 311}
312 312
313static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, 313static u32 iwl_fill_beacon_frame(struct iwl_priv *priv,
314 struct ieee80211_hdr *hdr, 314 struct ieee80211_hdr *hdr,
315 int left) 315 int left)
316{ 316{
@@ -327,34 +327,74 @@ static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
327 return priv->ibss_beacon->len; 327 return priv->ibss_beacon->len;
328} 328}
329 329
330/* Parse the beacon frame to find the TIM element and set tim_idx & tim_size */
331static void iwl_set_beacon_tim(struct iwl_priv *priv,
332 struct iwl_tx_beacon_cmd *tx_beacon_cmd,
333 u8 *beacon, u32 frame_size)
334{
335 u16 tim_idx;
336 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)beacon;
337
338 /*
339 * The index is relative to frame start but we start looking at the
340 * variable-length part of the beacon.
341 */
342 tim_idx = mgmt->u.beacon.variable - beacon;
343
344 /* Parse variable-length elements of beacon to find WLAN_EID_TIM */
345 while ((tim_idx < (frame_size - 2)) &&
346 (beacon[tim_idx] != WLAN_EID_TIM))
347 tim_idx += beacon[tim_idx+1] + 2;
348
349 /* If TIM field was found, set variables */
350 if ((tim_idx < (frame_size - 1)) && (beacon[tim_idx] == WLAN_EID_TIM)) {
351 tx_beacon_cmd->tim_idx = cpu_to_le16(tim_idx);
352 tx_beacon_cmd->tim_size = beacon[tim_idx+1];
353 } else
354 IWL_WARN(priv, "Unable to find TIM Element in beacon\n");
355}
356
330static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, 357static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
331 struct iwl_frame *frame, u8 rate) 358 struct iwl_frame *frame)
332{ 359{
333 struct iwl_tx_beacon_cmd *tx_beacon_cmd; 360 struct iwl_tx_beacon_cmd *tx_beacon_cmd;
334 unsigned int frame_size; 361 u32 frame_size;
362 u32 rate_flags;
363 u32 rate;
364 /*
365 * We have to set up the TX command, the TX Beacon command, and the
366 * beacon contents.
367 */
335 368
369 /* Initialize memory */
336 tx_beacon_cmd = &frame->u.beacon; 370 tx_beacon_cmd = &frame->u.beacon;
337 memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd)); 371 memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
338 372
339 tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id; 373 /* Set up TX beacon contents */
340 tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
341
342 frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame, 374 frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame,
343 sizeof(frame->u) - sizeof(*tx_beacon_cmd)); 375 sizeof(frame->u) - sizeof(*tx_beacon_cmd));
376 if (WARN_ON_ONCE(frame_size > MAX_MPDU_SIZE))
377 return 0;
344 378
345 BUG_ON(frame_size > MAX_MPDU_SIZE); 379 /* Set up TX command fields */
346 tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size); 380 tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);
381 tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id;
382 tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
383 tx_beacon_cmd->tx.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK |
384 TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK;
347 385
348 if ((rate == IWL_RATE_1M_PLCP) || (rate >= IWL_RATE_2M_PLCP)) 386 /* Set up TX beacon command fields */
349 tx_beacon_cmd->tx.rate_n_flags = 387 iwl_set_beacon_tim(priv, tx_beacon_cmd, (u8 *)tx_beacon_cmd->frame,
350 iwl_hw_set_rate_n_flags(rate, RATE_MCS_CCK_MSK); 388 frame_size);
351 else
352 tx_beacon_cmd->tx.rate_n_flags =
353 iwl_hw_set_rate_n_flags(rate, 0);
354 389
355 tx_beacon_cmd->tx.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK | 390 /* Set up packet rate and flags */
356 TX_CMD_FLG_TSF_MSK | 391 rate = iwl_rate_get_lowest_plcp(priv);
357 TX_CMD_FLG_STA_RATE_MSK; 392 priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant);
393 rate_flags = iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
394 if ((rate >= IWL_FIRST_CCK_RATE) && (rate <= IWL_LAST_CCK_RATE))
395 rate_flags |= RATE_MCS_CCK_MSK;
396 tx_beacon_cmd->tx.rate_n_flags = iwl_hw_set_rate_n_flags(rate,
397 rate_flags);
358 398
359 return sizeof(*tx_beacon_cmd) + frame_size; 399 return sizeof(*tx_beacon_cmd) + frame_size;
360} 400}
@@ -363,19 +403,20 @@ static int iwl_send_beacon_cmd(struct iwl_priv *priv)
363 struct iwl_frame *frame; 403 struct iwl_frame *frame;
364 unsigned int frame_size; 404 unsigned int frame_size;
365 int rc; 405 int rc;
366 u8 rate;
367 406
368 frame = iwl_get_free_frame(priv); 407 frame = iwl_get_free_frame(priv);
369
370 if (!frame) { 408 if (!frame) {
371 IWL_ERR(priv, "Could not obtain free frame buffer for beacon " 409 IWL_ERR(priv, "Could not obtain free frame buffer for beacon "
372 "command.\n"); 410 "command.\n");
373 return -ENOMEM; 411 return -ENOMEM;
374 } 412 }
375 413
376 rate = iwl_rate_get_lowest_plcp(priv); 414 frame_size = iwl_hw_get_beacon_cmd(priv, frame);
377 415 if (!frame_size) {
378 frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate); 416 IWL_ERR(priv, "Error configuring the beacon command\n");
417 iwl_free_frame(priv, frame);
418 return -EINVAL;
419 }
379 420
380 rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, 421 rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size,
381 &frame->u.cmd[0]); 422 &frame->u.cmd[0]);
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 1736c60c3e21..33da44f96e9f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -208,6 +208,7 @@ u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant)
208 } 208 }
209 return ant; 209 return ant;
210} 210}
211EXPORT_SYMBOL(iwl_toggle_tx_ant);
211 212
212const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 213const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
213EXPORT_SYMBOL(iwl_bcast_addr); 214EXPORT_SYMBOL(iwl_bcast_addr);