diff options
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 83 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.c | 1 |
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 | ||
313 | static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, | 313 | static 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 */ | ||
331 | static 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 | |||
330 | static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, | 357 | static 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 | } |
211 | EXPORT_SYMBOL(iwl_toggle_tx_ant); | ||
211 | 212 | ||
212 | const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; | 213 | const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; |
213 | EXPORT_SYMBOL(iwl_bcast_addr); | 214 | EXPORT_SYMBOL(iwl_bcast_addr); |