aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-agn.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c83
1 files changed, 62 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]);