aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/rx.c
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2009-01-08 06:32:06 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-01-29 16:00:05 -0500
commitfea147328908b7e2bfcaf9dc4377909d5507ca35 (patch)
tree4fa92b2ed01a5b4ec06d41b299606ed4546c09a1 /net/mac80211/rx.c
parentfdfacf0ae2e8339098b1164d2317b792d7662c0a (diff)
mac80211: 802.11w - SA Query processing
Process SA Query Requests for client mode in mac80211. AP side processing of SA Query Response frames is in user space (hostapd). Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com> Acked-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/rx.c')
-rw-r--r--net/mac80211/rx.c69
1 files changed, 69 insertions, 0 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index abc3aa583ca6..63db89aef3e4 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1667,6 +1667,57 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
1667 return RX_CONTINUE; 1667 return RX_CONTINUE;
1668} 1668}
1669 1669
1670void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
1671 struct ieee80211_mgmt *mgmt,
1672 size_t len)
1673{
1674 struct ieee80211_local *local = sdata->local;
1675 struct sk_buff *skb;
1676 struct ieee80211_mgmt *resp;
1677
1678 if (compare_ether_addr(mgmt->da, sdata->dev->dev_addr) != 0) {
1679 /* Not to own unicast address */
1680 return;
1681 }
1682
1683 if (compare_ether_addr(mgmt->sa, sdata->u.sta.bssid) != 0 ||
1684 compare_ether_addr(mgmt->bssid, sdata->u.sta.bssid) != 0) {
1685 /* Not from the current AP. */
1686 return;
1687 }
1688
1689 if (sdata->u.sta.state == IEEE80211_STA_MLME_ASSOCIATE) {
1690 /* Association in progress; ignore SA Query */
1691 return;
1692 }
1693
1694 if (len < 24 + 1 + sizeof(resp->u.action.u.sa_query)) {
1695 /* Too short SA Query request frame */
1696 return;
1697 }
1698
1699 skb = dev_alloc_skb(sizeof(*resp) + local->hw.extra_tx_headroom);
1700 if (skb == NULL)
1701 return;
1702
1703 skb_reserve(skb, local->hw.extra_tx_headroom);
1704 resp = (struct ieee80211_mgmt *) skb_put(skb, 24);
1705 memset(resp, 0, 24);
1706 memcpy(resp->da, mgmt->sa, ETH_ALEN);
1707 memcpy(resp->sa, sdata->dev->dev_addr, ETH_ALEN);
1708 memcpy(resp->bssid, sdata->u.sta.bssid, ETH_ALEN);
1709 resp->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
1710 IEEE80211_STYPE_ACTION);
1711 skb_put(skb, 1 + sizeof(resp->u.action.u.sa_query));
1712 resp->u.action.category = WLAN_CATEGORY_SA_QUERY;
1713 resp->u.action.u.sa_query.action = WLAN_ACTION_SA_QUERY_RESPONSE;
1714 memcpy(resp->u.action.u.sa_query.trans_id,
1715 mgmt->u.action.u.sa_query.trans_id,
1716 WLAN_SA_QUERY_TR_ID_LEN);
1717
1718 ieee80211_tx_skb(sdata, skb, 1);
1719}
1720
1670static ieee80211_rx_result debug_noinline 1721static ieee80211_rx_result debug_noinline
1671ieee80211_rx_h_action(struct ieee80211_rx_data *rx) 1722ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
1672{ 1723{
@@ -1743,6 +1794,24 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
1743 break; 1794 break;
1744 } 1795 }
1745 break; 1796 break;
1797 case WLAN_CATEGORY_SA_QUERY:
1798 if (len < (IEEE80211_MIN_ACTION_SIZE +
1799 sizeof(mgmt->u.action.u.sa_query)))
1800 return RX_DROP_MONITOR;
1801 switch (mgmt->u.action.u.sa_query.action) {
1802 case WLAN_ACTION_SA_QUERY_REQUEST:
1803 if (sdata->vif.type != NL80211_IFTYPE_STATION)
1804 return RX_DROP_MONITOR;
1805 ieee80211_process_sa_query_req(sdata, mgmt, len);
1806 break;
1807 case WLAN_ACTION_SA_QUERY_RESPONSE:
1808 /*
1809 * SA Query response is currently only used in AP mode
1810 * and it is processed in user space.
1811 */
1812 return RX_CONTINUE;
1813 }
1814 break;
1746 default: 1815 default:
1747 return RX_CONTINUE; 1816 return RX_CONTINUE;
1748 } 1817 }