From ec634fe328182a1a098585bfc7b69e5042bdb08d Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sun, 5 Jul 2009 19:23:38 -0700 Subject: net: convert remaining non-symbolic return values in ndo_start_xmit() functions This patch converts the remaining occurences of raw return values to their symbolic counterparts in ndo_start_xmit() functions that were missed by the previous automatic conversion. Additionally code that assumed the symbolic value of NETDEV_TX_OK to be zero is changed to explicitly use NETDEV_TX_OK. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/mac80211/tx.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index d238a8939a09..2ffb35d3f566 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1627,7 +1627,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, u32 sta_flags = 0; if (unlikely(skb->len < ETH_HLEN)) { - ret = 0; + ret = NETDEV_TX_OK; goto fail; } @@ -1664,7 +1664,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, if (!sdata->u.mesh.mshcfg.dot11MeshTTL) { /* Do not send frames with mesh_ttl == 0 */ sdata->u.mesh.mshstats.dropped_frames_ttl++; - ret = 0; + ret = NETDEV_TX_OK; goto fail; } memset(&mesh_hdr, 0, sizeof(mesh_hdr)); @@ -1724,7 +1724,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, hdrlen = 24; break; default: - ret = 0; + ret = NETDEV_TX_OK; goto fail; } @@ -1766,7 +1766,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, I802_DEBUG_INC(local->tx_handlers_drop_unauth_port); - ret = 0; + ret = NETDEV_TX_OK; goto fail; } @@ -1858,10 +1858,10 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, dev->trans_start = jiffies; dev_queue_xmit(skb); - return 0; + return NETDEV_TX_OK; fail: - if (!ret) + if (ret == NETDEV_TX_OK) dev_kfree_skb(skb); return ret; -- cgit v1.2.3 From e36d56b64808aec54b68b4e9976180c1da0933b2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 9 Jun 2009 21:04:43 +0200 Subject: cfg80211: pass netdev to change_virtual_intf If there was a reason I'm passing the ifidx I cannot remember it any more and don't see one now, so let's just pass the pointer itself. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 3f47276caeb8..eb93eb6a9cc7 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -74,19 +74,14 @@ static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) return 0; } -static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, +static int ieee80211_change_iface(struct wiphy *wiphy, + struct net_device *dev, enum nl80211_iftype type, u32 *flags, struct vif_params *params) { - struct net_device *dev; struct ieee80211_sub_if_data *sdata; int ret; - /* we're under RTNL */ - dev = __dev_get_by_index(&init_net, ifindex); - if (!dev) - return -ENODEV; - if (!nl80211_type_check(type)) return -EINVAL; -- cgit v1.2.3 From f1d58c2521eb160178b2151d6326d8dc5d7c8560 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 17 Jun 2009 13:13:00 +0200 Subject: mac80211: push rx status into skb->cb Within mac80211, we often need to copy the rx status into skb->cb. This is wasteful, as drivers could be building it in there to start with. This patch changes the API so that drivers are expected to pass the RX status in skb->cb, now accessible as IEEE80211_SKB_RXCB(skb). It also updates all drivers to pass the rx status in there, but only by making them memcpy() it into place before the call to the receive function (ieee80211_rx(_irqsafe)). Each driver can now be optimised on its own schedule. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ibss.c | 6 ++-- net/mac80211/ieee80211_i.h | 10 ++----- net/mac80211/main.c | 5 +--- net/mac80211/mesh.c | 6 ++-- net/mac80211/mesh.h | 3 +- net/mac80211/mlme.c | 4 +-- net/mac80211/rx.c | 71 ++++++++++++++++++++-------------------------- net/mac80211/scan.c | 4 +-- 8 files changed, 43 insertions(+), 66 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 0b30277eb366..15d5a53b59a8 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -705,7 +705,7 @@ static void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt; u16 fc; - rx_status = (struct ieee80211_rx_status *) skb->cb; + rx_status = IEEE80211_SKB_RXCB(skb); mgmt = (struct ieee80211_mgmt *) skb->data; fc = le16_to_cpu(mgmt->frame_control); @@ -836,8 +836,7 @@ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local) } ieee80211_rx_result -ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, - struct ieee80211_rx_status *rx_status) +ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { struct ieee80211_local *local = sdata->local; struct ieee80211_mgmt *mgmt; @@ -852,7 +851,6 @@ ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, switch (fc & IEEE80211_FCTL_STYPE) { case IEEE80211_STYPE_PROBE_RESP: case IEEE80211_STYPE_BEACON: - memcpy(skb->cb, rx_status, sizeof(*rx_status)); case IEEE80211_STYPE_PROBE_REQ: case IEEE80211_STYPE_AUTH: skb_queue_tail(&sdata->u.ibss.skb_queue, skb); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 68eb5052179a..c65c65a9e697 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -943,8 +943,7 @@ extern const struct iw_handler_def ieee80211_iw_handler_def; /* STA code */ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata); ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, - struct ieee80211_rx_status *rx_status); + struct sk_buff *skb); int ieee80211_sta_commit(struct ieee80211_sub_if_data *sdata); int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len); int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len); @@ -967,8 +966,7 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata); void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata); ieee80211_rx_result -ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, - struct ieee80211_rx_status *rx_status); +ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, u8 *bssid, u8 *addr, u32 supp_rates); int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, @@ -988,9 +986,7 @@ int ieee80211_scan_results(struct ieee80211_local *local, char *buf, size_t len); void ieee80211_scan_cancel(struct ieee80211_local *local); ieee80211_rx_result -ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, - struct ieee80211_rx_status *rx_status); +ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, const char *ie, size_t len); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 092a017b237e..5b69f5f07299 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -330,19 +330,16 @@ static void ieee80211_tasklet_handler(unsigned long data) { struct ieee80211_local *local = (struct ieee80211_local *) data; struct sk_buff *skb; - struct ieee80211_rx_status rx_status; struct ieee80211_ra_tid *ra_tid; while ((skb = skb_dequeue(&local->skb_queue)) || (skb = skb_dequeue(&local->skb_queue_unreliable))) { switch (skb->pkt_type) { case IEEE80211_RX_MSG: - /* status is in skb->cb */ - memcpy(&rx_status, skb->cb, sizeof(rx_status)); /* Clear skb->pkt_type in order to not confuse kernel * netstack. */ skb->pkt_type = 0; - __ieee80211_rx(local_to_hw(local), skb, &rx_status); + ieee80211_rx(local_to_hw(local), skb); break; case IEEE80211_TX_STATUS_MSG: skb->pkt_type = 0; diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 11cf45bce38a..542ea025494e 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -568,7 +568,7 @@ static void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, ifmsh = &sdata->u.mesh; - rx_status = (struct ieee80211_rx_status *) skb->cb; + rx_status = IEEE80211_SKB_RXCB(skb); mgmt = (struct ieee80211_mgmt *) skb->data; stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE; @@ -671,8 +671,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) } ieee80211_rx_result -ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, - struct ieee80211_rx_status *rx_status) +ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { struct ieee80211_local *local = sdata->local; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; @@ -689,7 +688,6 @@ ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, case IEEE80211_STYPE_PROBE_RESP: case IEEE80211_STYPE_BEACON: case IEEE80211_STYPE_ACTION: - memcpy(skb->cb, rx_status, sizeof(*rx_status)); skb_queue_tail(&ifmsh->skb_queue, skb); queue_work(local->hw.workqueue, &ifmsh->work); return RX_QUEUED; diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index c7d72819cdd2..2a2ed182cb7e 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -208,8 +208,7 @@ void ieee80211s_init(void); void ieee80211s_stop(void); void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata); ieee80211_rx_result -ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, - struct ieee80211_rx_status *rx_status); +ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index aca22b00b6a3..5e25d320deae 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2063,8 +2063,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, } ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, - struct ieee80211_rx_status *rx_status) + struct sk_buff *skb) { struct ieee80211_local *local = sdata->local; struct ieee80211_mgmt *mgmt; @@ -2080,7 +2079,6 @@ ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, case IEEE80211_STYPE_PROBE_REQ: case IEEE80211_STYPE_PROBE_RESP: case IEEE80211_STYPE_BEACON: - memcpy(skb->cb, rx_status, sizeof(*rx_status)); case IEEE80211_STYPE_AUTH: case IEEE80211_STYPE_ASSOC_RESP: case IEEE80211_STYPE_REASSOC_RESP: diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index de5bba7f910a..0563b6969a21 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -30,7 +30,6 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, struct tid_ampdu_rx *tid_agg_rx, struct sk_buff *skb, - struct ieee80211_rx_status *status, u16 mpdu_seq_num, int bar_req); /* @@ -59,11 +58,11 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, return skb; } -static inline int should_drop_frame(struct ieee80211_rx_status *status, - struct sk_buff *skb, +static inline int should_drop_frame(struct sk_buff *skb, int present_fcs_len, int radiotap_len) { + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) @@ -111,10 +110,10 @@ ieee80211_rx_radiotap_len(struct ieee80211_local *local, static void ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, struct sk_buff *skb, - struct ieee80211_rx_status *status, struct ieee80211_rate *rate, int rtap_len) { + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_radiotap_header *rthdr; unsigned char *pos; @@ -220,9 +219,9 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, */ static struct sk_buff * ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, - struct ieee80211_rx_status *status, struct ieee80211_rate *rate) { + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(origskb); struct ieee80211_sub_if_data *sdata; int needed_headroom = 0; struct sk_buff *skb, *skb2; @@ -248,8 +247,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, present_fcs_len = FCS_LEN; if (!local->monitors) { - if (should_drop_frame(status, origskb, present_fcs_len, - rtap_len)) { + if (should_drop_frame(origskb, present_fcs_len, rtap_len)) { dev_kfree_skb(origskb); return NULL; } @@ -257,7 +255,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, return remove_monitor_info(local, origskb, rtap_len); } - if (should_drop_frame(status, origskb, present_fcs_len, rtap_len)) { + if (should_drop_frame(origskb, present_fcs_len, rtap_len)) { /* only need to expand headroom if necessary */ skb = origskb; origskb = NULL; @@ -289,7 +287,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, /* if necessary, prepend radiotap information */ if (!(status->flag & RX_FLAG_RADIOTAP)) - ieee80211_add_rx_radiotap_header(local, skb, status, rate, + ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom); skb_reset_mac_header(skb); @@ -421,12 +419,11 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx) struct sk_buff *skb = rx->skb; if (unlikely(local->hw_scanning)) - return ieee80211_scan_rx(rx->sdata, skb, rx->status); + return ieee80211_scan_rx(rx->sdata, skb); if (unlikely(local->sw_scanning)) { /* drop all the other packets during a software scan anyway */ - if (ieee80211_scan_rx(rx->sdata, skb, rx->status) - != RX_QUEUED) + if (ieee80211_scan_rx(rx->sdata, skb) != RX_QUEUED) dev_kfree_skb(skb); return RX_QUEUED; } @@ -1620,7 +1617,7 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) /* manage reordering buffer according to requested */ /* sequence number */ rcu_read_lock(); - ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL, NULL, + ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL, start_seq_num, 1); rcu_read_unlock(); return RX_DROP_UNUSABLE; @@ -1817,13 +1814,13 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) return RX_DROP_MONITOR; if (ieee80211_vif_is_mesh(&sdata->vif)) - return ieee80211_mesh_rx_mgmt(sdata, rx->skb, rx->status); + return ieee80211_mesh_rx_mgmt(sdata, rx->skb); if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - return ieee80211_ibss_rx_mgmt(sdata, rx->skb, rx->status); + return ieee80211_ibss_rx_mgmt(sdata, rx->skb); if (sdata->vif.type == NL80211_IFTYPE_STATION) - return ieee80211_sta_rx_mgmt(sdata, rx->skb, rx->status); + return ieee80211_sta_rx_mgmt(sdata, rx->skb); return RX_DROP_MONITOR; } @@ -2114,9 +2111,9 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, */ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_rx_status *status, struct ieee80211_rate *rate) { + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; struct ieee80211_hdr *hdr; @@ -2227,20 +2224,21 @@ static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw, { struct ieee80211_supported_band *sband; struct ieee80211_rate *rate; - struct ieee80211_rx_status status; + struct sk_buff *skb = tid_agg_rx->reorder_buf[index]; + struct ieee80211_rx_status *status; - if (!tid_agg_rx->reorder_buf[index]) + if (!skb) goto no_frame; + status = IEEE80211_SKB_RXCB(skb); + /* release the reordered frames to stack */ - memcpy(&status, tid_agg_rx->reorder_buf[index]->cb, sizeof(status)); - sband = hw->wiphy->bands[status.band]; - if (status.flag & RX_FLAG_HT) + sband = hw->wiphy->bands[status->band]; + if (status->flag & RX_FLAG_HT) rate = sband->bitrates; /* TODO: HT rates */ else - rate = &sband->bitrates[status.rate_idx]; - __ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index], - &status, rate); + rate = &sband->bitrates[status->rate_idx]; + __ieee80211_rx_handle_packet(hw, skb, rate); tid_agg_rx->stored_mpdu_num--; tid_agg_rx->reorder_buf[index] = NULL; @@ -2265,7 +2263,6 @@ no_frame: static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, struct tid_ampdu_rx *tid_agg_rx, struct sk_buff *skb, - struct ieee80211_rx_status *rxstatus, u16 mpdu_seq_num, int bar_req) { @@ -2324,8 +2321,6 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, /* put the frame in the reordering buffer */ tid_agg_rx->reorder_buf[index] = skb; tid_agg_rx->reorder_time[index] = jiffies; - memcpy(tid_agg_rx->reorder_buf[index]->cb, rxstatus, - sizeof(*rxstatus)); tid_agg_rx->stored_mpdu_num++; /* release the buffer until next missing frame */ index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) @@ -2374,8 +2369,7 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, } static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, - struct sk_buff *skb, - struct ieee80211_rx_status *status) + struct sk_buff *skb) { struct ieee80211_hw *hw = &local->hw; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; @@ -2424,7 +2418,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, /* according to mpdu sequence number deal with reordering buffer */ mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; - ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, status, + ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, mpdu_seq_num, 0); end_reorder: return ret; @@ -2434,12 +2428,12 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, * This is the receive path handler. It is called by a low level driver when an * 802.11 MPDU is received from the hardware. */ -void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_rx_status *status) +void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_rate *rate = NULL; struct ieee80211_supported_band *sband; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); if (status->band < 0 || status->band >= IEEE80211_NUM_BANDS) { @@ -2482,7 +2476,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, * if it was previously present. * Also, frames with less than 16 bytes are dropped. */ - skb = ieee80211_rx_monitor(local, skb, status, rate); + skb = ieee80211_rx_monitor(local, skb, rate); if (!skb) { rcu_read_unlock(); return; @@ -2500,8 +2494,8 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, * frames from other than operational channel), but that should not * happen in normal networks. */ - if (!ieee80211_rx_reorder_ampdu(local, skb, status)) - __ieee80211_rx_handle_packet(hw, skb, status, rate); + if (!ieee80211_rx_reorder_ampdu(local, skb)) + __ieee80211_rx_handle_packet(hw, skb, rate); rcu_read_unlock(); } @@ -2509,16 +2503,13 @@ EXPORT_SYMBOL(__ieee80211_rx); /* This is a version of the rx handler that can be called from hard irq * context. Post the skb on the queue and schedule the tasklet */ -void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_rx_status *status) +void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ieee80211_local *local = hw_to_local(hw); BUILD_BUG_ON(sizeof(struct ieee80211_rx_status) > sizeof(skb->cb)); skb->dev = local->mdev; - /* copy status into skb->cb for use by tasklet */ - memcpy(skb->cb, status, sizeof(*status)); skb->pkt_type = IEEE80211_RX_MSG; skb_queue_tail(&local->skb_queue, skb); tasklet_schedule(&local->tasklet); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 2a8d09ad17ff..8b2416c77a6e 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -135,9 +135,9 @@ void ieee80211_rx_bss_remove(struct ieee80211_sub_if_data *sdata, u8 *bssid, } ieee80211_rx_result -ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, - struct ieee80211_rx_status *rx_status) +ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { + struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); struct ieee80211_mgmt *mgmt; struct ieee80211_bss *bss; u8 *elements; -- cgit v1.2.3 From 386aa23dd5f94b810210b9f849807946a5100b57 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 17 Jun 2009 17:28:45 +0200 Subject: mac80211: improve per-sta debugfs We had code for a number of files, that we didn't publish in debugfs, fix that. Also make the agg_status file layout more readable and add more information to it. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/debugfs_sta.c | 98 +++++++++++++++++++++++++++++----------------- net/mac80211/sta_info.h | 17 ++++++++ 2 files changed, 79 insertions(+), 36 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 90230c718b5b..33a2e892115b 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -120,45 +120,38 @@ STA_OPS(last_seq_ctrl); static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { - char buf[768], *p = buf; + char buf[30 + STA_TID_NUM * 70], *p = buf; int i; struct sta_info *sta = file->private_data; - p += scnprintf(p, sizeof(buf)+buf-p, "Agg state for STA is:\n"); - p += scnprintf(p, sizeof(buf)+buf-p, " STA next dialog_token is %d \n " - "TIDs info is: \n TID :", - (sta->ampdu_mlme.dialog_token_allocator + 1)); - for (i = 0; i < STA_TID_NUM; i++) - p += scnprintf(p, sizeof(buf)+buf-p, "%5d", i); - - p += scnprintf(p, sizeof(buf)+buf-p, "\n RX :"); - for (i = 0; i < STA_TID_NUM; i++) - p += scnprintf(p, sizeof(buf)+buf-p, "%5d", - sta->ampdu_mlme.tid_state_rx[i]); - - p += scnprintf(p, sizeof(buf)+buf-p, "\n DTKN:"); - for (i = 0; i < STA_TID_NUM; i++) - p += scnprintf(p, sizeof(buf)+buf-p, "%5d", - sta->ampdu_mlme.tid_state_rx[i] ? - sta->ampdu_mlme.tid_rx[i]->dialog_token : 0); - - p += scnprintf(p, sizeof(buf)+buf-p, "\n TX :"); - for (i = 0; i < STA_TID_NUM; i++) - p += scnprintf(p, sizeof(buf)+buf-p, "%5d", - sta->ampdu_mlme.tid_state_tx[i]); - - p += scnprintf(p, sizeof(buf)+buf-p, "\n DTKN:"); - for (i = 0; i < STA_TID_NUM; i++) - p += scnprintf(p, sizeof(buf)+buf-p, "%5d", - sta->ampdu_mlme.tid_state_tx[i] ? - sta->ampdu_mlme.tid_tx[i]->dialog_token : 0); - - p += scnprintf(p, sizeof(buf)+buf-p, "\n SSN :"); - for (i = 0; i < STA_TID_NUM; i++) - p += scnprintf(p, sizeof(buf)+buf-p, "%5d", - sta->ampdu_mlme.tid_state_tx[i] ? - sta->ampdu_mlme.tid_tx[i]->ssn : 0); - p += scnprintf(p, sizeof(buf)+buf-p, "\n"); + spin_lock_bh(&sta->lock); + p += scnprintf(p, sizeof(buf)+buf-p, "next dialog_token is %#02x\n", + sta->ampdu_mlme.dialog_token_allocator + 1); + for (i = 0; i < STA_TID_NUM; i++) { + p += scnprintf(p, sizeof(buf)+buf-p, "TID %02d:", i); + p += scnprintf(p, sizeof(buf)+buf-p, " RX=%x", + sta->ampdu_mlme.tid_state_rx[i]); + p += scnprintf(p, sizeof(buf)+buf-p, "/DTKN=%#.2x", + sta->ampdu_mlme.tid_state_rx[i] ? + sta->ampdu_mlme.tid_rx[i]->dialog_token : 0); + p += scnprintf(p, sizeof(buf)+buf-p, "/SSN=%#.3x", + sta->ampdu_mlme.tid_state_rx[i] ? + sta->ampdu_mlme.tid_rx[i]->ssn : 0); + + p += scnprintf(p, sizeof(buf)+buf-p, " TX=%x", + sta->ampdu_mlme.tid_state_tx[i]); + p += scnprintf(p, sizeof(buf)+buf-p, "/DTKN=%#.2x", + sta->ampdu_mlme.tid_state_tx[i] ? + sta->ampdu_mlme.tid_tx[i]->dialog_token : 0); + p += scnprintf(p, sizeof(buf)+buf-p, "/SSN=%#.3x", + sta->ampdu_mlme.tid_state_tx[i] ? + sta->ampdu_mlme.tid_tx[i]->ssn : 0); + p += scnprintf(p, sizeof(buf)+buf-p, "/pending=%03d", + sta->ampdu_mlme.tid_state_tx[i] ? + skb_queue_len(&sta->ampdu_mlme.tid_tx[i]->pending) : 0); + p += scnprintf(p, sizeof(buf)+buf-p, "\n"); + } + spin_unlock_bh(&sta->lock); return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); } @@ -203,6 +196,22 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) DEBUGFS_ADD(inactive_ms); DEBUGFS_ADD(last_seq_ctrl); DEBUGFS_ADD(agg_status); + DEBUGFS_ADD(dev); + DEBUGFS_ADD(rx_packets); + DEBUGFS_ADD(tx_packets); + DEBUGFS_ADD(rx_bytes); + DEBUGFS_ADD(tx_bytes); + DEBUGFS_ADD(rx_duplicates); + DEBUGFS_ADD(rx_fragments); + DEBUGFS_ADD(rx_dropped); + DEBUGFS_ADD(tx_fragments); + DEBUGFS_ADD(tx_filtered); + DEBUGFS_ADD(tx_retry_failed); + DEBUGFS_ADD(tx_retry_count); + DEBUGFS_ADD(last_signal); + DEBUGFS_ADD(last_qual); + DEBUGFS_ADD(last_noise); + DEBUGFS_ADD(wep_weak_iv_count); } void ieee80211_sta_debugfs_remove(struct sta_info *sta) @@ -212,6 +221,23 @@ void ieee80211_sta_debugfs_remove(struct sta_info *sta) DEBUGFS_DEL(inactive_ms); DEBUGFS_DEL(last_seq_ctrl); DEBUGFS_DEL(agg_status); + DEBUGFS_DEL(aid); + DEBUGFS_DEL(dev); + DEBUGFS_DEL(rx_packets); + DEBUGFS_DEL(tx_packets); + DEBUGFS_DEL(rx_bytes); + DEBUGFS_DEL(tx_bytes); + DEBUGFS_DEL(rx_duplicates); + DEBUGFS_DEL(rx_fragments); + DEBUGFS_DEL(rx_dropped); + DEBUGFS_DEL(tx_fragments); + DEBUGFS_DEL(tx_filtered); + DEBUGFS_DEL(tx_retry_failed); + DEBUGFS_DEL(tx_retry_count); + DEBUGFS_DEL(last_signal); + DEBUGFS_DEL(last_qual); + DEBUGFS_DEL(last_noise); + DEBUGFS_DEL(wep_weak_iv_count); debugfs_remove(sta->debugfs.dir); sta->debugfs.dir = NULL; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 49a1a1f76511..4ecf10a9bd00 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -308,6 +308,23 @@ struct sta_info { struct dentry *inactive_ms; struct dentry *last_seq_ctrl; struct dentry *agg_status; + struct dentry *aid; + struct dentry *dev; + struct dentry *rx_packets; + struct dentry *tx_packets; + struct dentry *rx_bytes; + struct dentry *tx_bytes; + struct dentry *rx_duplicates; + struct dentry *rx_fragments; + struct dentry *rx_dropped; + struct dentry *tx_fragments; + struct dentry *tx_filtered; + struct dentry *tx_retry_failed; + struct dentry *tx_retry_count; + struct dentry *last_signal; + struct dentry *last_qual; + struct dentry *last_noise; + struct dentry *wep_weak_iv_count; bool add_has_run; } debugfs; #endif -- cgit v1.2.3 From f58d4ed98bfe7b2febcd6f0d62744b623e4b8371 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 19 Jun 2009 02:45:21 +0200 Subject: cfg80211: send wext MLME-MICHAELMICFAILURE.indication Instead of having mac80211 do it itself. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/event.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/event.c b/net/mac80211/event.c index f288d01a6344..3ac636285fb1 100644 --- a/net/mac80211/event.c +++ b/net/mac80211/event.c @@ -7,8 +7,7 @@ * * mac80211 - events */ - -#include +#include #include "ieee80211_i.h" /* @@ -19,21 +18,6 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx, struct ieee80211_hdr *hdr, const u8 *tsc) { - union iwreq_data wrqu; - char *buf = kmalloc(128, GFP_ATOMIC); - - if (buf) { - /* TODO: needed parameters: count, key type, TSC */ - sprintf(buf, "MLME-MICHAELMICFAILURE.indication(" - "keyid=%d %scast addr=%pM)", - keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni", - hdr->addr2); - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = strlen(buf); - wireless_send_event(sdata->dev, IWEVCUSTOM, &wrqu, buf); - kfree(buf); - } - cfg80211_michael_mic_failure(sdata->dev, hdr->addr2, (hdr->addr1[0] & 0x01) ? NL80211_KEYTYPE_GROUP : -- cgit v1.2.3 From d3cebbdcedf8d1519913f6e9bf88dbac7fbaa760 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:26:43 +0200 Subject: mac80211: fix todo lock The key todo lock can be taken from different locks that require it to be _bh to avoid lock inversion due to (soft)irqs. This should fix the two problems reported by Bob and Gabor: http://mid.gmane.org/20090619113049.GB18956@hash.localnet http://mid.gmane.org/4A3FA376.8020307@openwrt.org Signed-off-by: Johannes Berg Cc: Bob Copeland Cc: Gabor Juhos Signed-off-by: John W. Linville --- net/mac80211/key.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/key.c b/net/mac80211/key.c index ce267565e180..659a42d529e3 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -67,6 +67,8 @@ static DECLARE_WORK(todo_work, key_todo); * * @key: key to add to do item for * @flag: todo flag(s) + * + * Must be called with IRQs or softirqs disabled. */ static void add_todo(struct ieee80211_key *key, u32 flag) { @@ -140,9 +142,9 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) ret = drv_set_key(key->local, SET_KEY, &sdata->vif, sta, &key->conf); if (!ret) { - spin_lock(&todo_lock); + spin_lock_bh(&todo_lock); key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; - spin_unlock(&todo_lock); + spin_unlock_bh(&todo_lock); } if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP) @@ -164,12 +166,12 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) if (!key || !key->local->ops->set_key) return; - spin_lock(&todo_lock); + spin_lock_bh(&todo_lock); if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { - spin_unlock(&todo_lock); + spin_unlock_bh(&todo_lock); return; } - spin_unlock(&todo_lock); + spin_unlock_bh(&todo_lock); sta = get_sta_for_key(key); sdata = key->sdata; @@ -188,9 +190,9 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) wiphy_name(key->local->hw.wiphy), key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); - spin_lock(&todo_lock); + spin_lock_bh(&todo_lock); key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; - spin_unlock(&todo_lock); + spin_unlock_bh(&todo_lock); } static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, @@ -437,14 +439,14 @@ void ieee80211_key_link(struct ieee80211_key *key, __ieee80211_key_replace(sdata, sta, old_key, key); - spin_unlock_irqrestore(&sdata->local->key_lock, flags); - /* free old key later */ add_todo(old_key, KEY_FLAG_TODO_DELETE); add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS); if (netif_running(sdata->dev)) add_todo(key, KEY_FLAG_TODO_HWACCEL_ADD); + + spin_unlock_irqrestore(&sdata->local->key_lock, flags); } static void __ieee80211_key_free(struct ieee80211_key *key) @@ -547,7 +549,7 @@ static void __ieee80211_key_todo(void) */ synchronize_rcu(); - spin_lock(&todo_lock); + spin_lock_bh(&todo_lock); while (!list_empty(&todo_list)) { key = list_first_entry(&todo_list, struct ieee80211_key, todo); list_del_init(&key->todo); @@ -558,7 +560,7 @@ static void __ieee80211_key_todo(void) KEY_FLAG_TODO_HWACCEL_REMOVE | KEY_FLAG_TODO_DELETE); key->flags &= ~todoflags; - spin_unlock(&todo_lock); + spin_unlock_bh(&todo_lock); work_done = false; @@ -591,9 +593,9 @@ static void __ieee80211_key_todo(void) WARN_ON(!work_done); - spin_lock(&todo_lock); + spin_lock_bh(&todo_lock); } - spin_unlock(&todo_lock); + spin_unlock_bh(&todo_lock); } void ieee80211_key_todo(void) -- cgit v1.2.3 From e6d6e3420d511cd7552a95d1f04bd4c80a9ddb34 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:26:47 +0200 Subject: cfg80211: use proper allocation flags Instead of hardcoding GFP_ATOMIC everywhere, add a new function parameter that gets the flags from the caller. Obviously then I need to update all callers (all of them in mac80211), and it turns out that now it's ok to use GFP_KERNEL in almost all places. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/event.c | 5 +++-- net/mac80211/ieee80211_i.h | 3 ++- net/mac80211/mlme.c | 30 +++++++++++++++++++----------- net/mac80211/rx.c | 3 ++- net/mac80211/wpa.c | 3 ++- 5 files changed, 28 insertions(+), 16 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/event.c b/net/mac80211/event.c index 3ac636285fb1..01ae759518f6 100644 --- a/net/mac80211/event.c +++ b/net/mac80211/event.c @@ -16,11 +16,12 @@ * driver or is still in the frame), it should provide that information. */ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx, - struct ieee80211_hdr *hdr, const u8 *tsc) + struct ieee80211_hdr *hdr, const u8 *tsc, + gfp_t gfp) { cfg80211_michael_mic_failure(sdata->dev, hdr->addr2, (hdr->addr1[0] & 0x01) ? NL80211_KEYTYPE_GROUP : NL80211_KEYTYPE_PAIRWISE, - keyidx, tsc); + keyidx, tsc, gfp); } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c65c65a9e697..e0323e540a03 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1088,7 +1088,8 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, int rate, int erp, int short_preamble); void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int keyidx, - struct ieee80211_hdr *hdr, const u8 *tsc); + struct ieee80211_hdr *hdr, const u8 *tsc, + gfp_t gfp); void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata); void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, int encrypt); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 5e25d320deae..383392b04282 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -419,9 +419,11 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, mgmt->u.deauth.reason_code = cpu_to_le16(reason); if (stype == IEEE80211_STYPE_DEAUTH) - cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, skb->len); + cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, skb->len, + GFP_KERNEL); else - cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, skb->len); + cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, skb->len, + GFP_KERNEL); ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED); } @@ -1006,7 +1008,8 @@ static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata) sdata->dev->name, ifmgd->bssid); ifmgd->state = IEEE80211_STA_MLME_DISABLED; ieee80211_recalc_idle(local); - cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid); + cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid, + GFP_KERNEL); /* * Most likely AP is not in the range so remove the @@ -1055,7 +1058,8 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata) sdata->dev->name, ifmgd->bssid); ifmgd->state = IEEE80211_STA_MLME_DISABLED; ieee80211_recalc_idle(local); - cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid); + cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid, + GFP_KERNEL); ieee80211_rx_bss_remove(sdata, ifmgd->bssid, sdata->local->hw.conf.channel->center_freq, ifmgd->ssid, ifmgd->ssid_len); @@ -1243,7 +1247,8 @@ static void ieee80211_associate(struct ieee80211_sub_if_data *sdata) sdata->dev->name, ifmgd->bssid); ifmgd->state = IEEE80211_STA_MLME_DISABLED; ieee80211_recalc_idle(local); - cfg80211_send_assoc_timeout(sdata->dev, ifmgd->bssid); + cfg80211_send_assoc_timeout(sdata->dev, ifmgd->bssid, + GFP_KERNEL); ieee80211_rx_bss_remove(sdata, ifmgd->bssid, sdata->local->hw.conf.channel->center_freq, ifmgd->ssid, ifmgd->ssid_len); @@ -1517,12 +1522,14 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, case WLAN_AUTH_LEAP: case WLAN_AUTH_FT: ieee80211_auth_completed(sdata); - cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len); + cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len, + GFP_KERNEL); break; case WLAN_AUTH_SHARED_KEY: if (ifmgd->auth_transaction == 4) { ieee80211_auth_completed(sdata); - cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len); + cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len, + GFP_KERNEL); } else ieee80211_auth_challenge(sdata, mgmt, len); break; @@ -1560,7 +1567,7 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, ieee80211_set_disassoc(sdata, true, false, 0); ifmgd->flags &= ~IEEE80211_STA_AUTHENTICATED; - cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, len); + cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, len, GFP_KERNEL); } @@ -1591,7 +1598,7 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, } ieee80211_set_disassoc(sdata, false, false, reason_code); - cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, len); + cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, len, GFP_KERNEL); } @@ -1660,7 +1667,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, * association next time. This works around some broken APs * which do not correctly reject reassociation requests. */ ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET; - cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len); + cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len, + GFP_KERNEL); if (ifmgd->flags & IEEE80211_STA_EXT_SME) { /* Wait for SME to decide what to do next */ ifmgd->state = IEEE80211_STA_MLME_DISABLED; @@ -1823,7 +1831,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, ifmgd->last_beacon = jiffies; ieee80211_associated(sdata); - cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len); + cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len, GFP_KERNEL); } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 0563b6969a21..ec5acc6dc021 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1863,7 +1863,8 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, !ieee80211_is_auth(hdr->frame_control)) goto ignore; - mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr, NULL); + mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr, NULL, + GFP_ATOMIC); ignore: dev_kfree_skb(rx->skb); rx->skb = NULL; diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index dcfae8884b86..70778694877b 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -122,7 +122,8 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) return RX_DROP_UNUSABLE; mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx, - (void *) skb->data, NULL); + (void *) skb->data, NULL, + GFP_ATOMIC); return RX_DROP_UNUSABLE; } -- cgit v1.2.3 From 0575606b086ad216b7b1976ca9b9a6e711db92f0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:26:49 +0200 Subject: mac80211: tell SME about real auth state When the auth algorithm is rejected, but we don't have another one to try, we will eventually retry but that isn't useful -- we'll then do it again and again until we eventually give up. Instead, we should let the SME know and go into disabled state. The same applies for situations where the AP rejects with any other status code. Additionally, when trying the next auth algorithm, we should reset the auth_tries so that just a single lost frame doesn't lead to us giving up on the third auth algorithm. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 383392b04282..58135a5096af 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1511,9 +1511,15 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, !ieee80211_sta_wep_configured(sdata)) continue; ifmgd->auth_alg = algs[pos]; - break; + ifmgd->auth_tries = 0; + return; } } + /* nothing else to try -- give up */ + cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len, + GFP_KERNEL); + ifmgd->state = IEEE80211_STA_MLME_DISABLED; + ieee80211_recalc_idle(sdata->local); return; } -- cgit v1.2.3 From aff89a9b9084931e51b89d8f3ee3c547bea6c422 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:26:51 +0200 Subject: cfg80211: introduce nl80211 testmode command This introduces a new NL80211_CMD_TESTMODE for testing and calibration use with nl80211. There's no multiplexing like like iwpriv had, and the command is not available by default, it needs to be explicitly enabled in Kconfig and shouldn't be enabled in most kernels. The command requires a wiphy index or interface index to identify the device to operate on, and the new TESTDATA attribute. There also is API for sending replies to the command, and testmode multicast messages (on a testmode multicast group). I've also updated mac80211 to be able to pass through the command to the driver, since it itself doesn't implement the testmode command. Additionally, to give people an idea of how to use the command, I've added a little code to hwsim that makes use of the new command to set the powersave mode, this is currently done via debugfs and should remain there, and the testmode command only serves as an example of how to use this best -- with nested netlink attributes in the TESTDATA attribute. A hwsim testmode tool can be found at http://git.sipsolutions.net/hwsim.git/. This tool is BSD licensed so people can easily use it as a basis for their own internal fabrication and validation tools. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'net/mac80211') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index eb93eb6a9cc7..c34c1a41019a 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1376,6 +1376,18 @@ static void ieee80211_rfkill_poll(struct wiphy *wiphy) drv_rfkill_poll(local); } +#ifdef CONFIG_NL80211_TESTMODE +int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len) +{ + struct ieee80211_local *local = wiphy_priv(wiphy); + + if (!local->ops->testmode_cmd) + return -EOPNOTSUPP; + + return local->ops->testmode_cmd(&local->hw, data, len); +} +#endif + struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, @@ -1418,4 +1430,5 @@ struct cfg80211_ops mac80211_config_ops = { .set_tx_power = ieee80211_set_tx_power, .get_tx_power = ieee80211_get_tx_power, .rfkill_poll = ieee80211_rfkill_poll, + CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) }; -- cgit v1.2.3 From 3f65b24536996ac493777ef11474c47e1d3f56a0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:26:52 +0200 Subject: mac80211: remove an unused function declaration The ieee80211_scan_results function hasn't existed for a long time now, so its declaration should be removed as well. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index e0323e540a03..1950e2eb4150 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -981,9 +981,6 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, const u8 *ssid, u8 ssid_len); int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, struct cfg80211_scan_request *req); -int ieee80211_scan_results(struct ieee80211_local *local, - struct iw_request_info *info, - char *buf, size_t len); void ieee80211_scan_cancel(struct ieee80211_local *local); ieee80211_rx_result ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); -- cgit v1.2.3 From b23aa676ab9d54469cda9f7151f51a2851c6f36e Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 1 Jul 2009 21:26:54 +0200 Subject: cfg80211: connect/disconnect API This patch introduces the cfg80211 connect/disconnect API. The goal here is to run the AUTH and ASSOC steps in one call. This is needed for some fullmac cards that run both steps directly from the target, after the host driver sends a connect command. Additionally, all the new crypto parameters for connect() are now also valid for associate() -- although associate requires the IEs to be used, the information can be useful for drivers and should be given. Signed-off-by: Samuel Ortiz Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index c34c1a41019a..03de4024597a 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1262,7 +1262,7 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED; } - if (req->control_port) + if (req->crypto.control_port) sdata->u.mgd.flags |= IEEE80211_STA_CONTROL_PORT; else sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; -- cgit v1.2.3 From f21293549f60f88c74fcb9944737f11048896dc4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:26:56 +0200 Subject: cfg80211: managed mode wext compatibility This adds code to make it possible to use the cfg80211 connect() API with wireless extensions, and because the previous patch added emulation of that API with auth() and assoc(), by extension also supports wext on that. At the same time, removes code from mac80211 for wext, but doesn't yet clean up mac80211's mlme code more. Signed-off-by: Samuel Ortiz Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 69 ----------------- net/mac80211/wext.c | 215 +++++----------------------------------------------- 2 files changed, 20 insertions(+), 264 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 58135a5096af..fbb93a70ddc7 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -870,70 +870,6 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, return changed; } -static void ieee80211_sta_send_apinfo(struct ieee80211_sub_if_data *sdata) -{ - union iwreq_data wrqu; - - memset(&wrqu, 0, sizeof(wrqu)); - if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) - memcpy(wrqu.ap_addr.sa_data, sdata->u.mgd.bssid, ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL); -} - -static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata) -{ - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - char *buf; - size_t len; - int i; - union iwreq_data wrqu; - - if (!ifmgd->assocreq_ies && !ifmgd->assocresp_ies) - return; - - buf = kmalloc(50 + 2 * (ifmgd->assocreq_ies_len + - ifmgd->assocresp_ies_len), GFP_KERNEL); - if (!buf) - return; - - len = sprintf(buf, "ASSOCINFO("); - if (ifmgd->assocreq_ies) { - len += sprintf(buf + len, "ReqIEs="); - for (i = 0; i < ifmgd->assocreq_ies_len; i++) { - len += sprintf(buf + len, "%02x", - ifmgd->assocreq_ies[i]); - } - } - if (ifmgd->assocresp_ies) { - if (ifmgd->assocreq_ies) - len += sprintf(buf + len, " "); - len += sprintf(buf + len, "RespIEs="); - for (i = 0; i < ifmgd->assocresp_ies_len; i++) { - len += sprintf(buf + len, "%02x", - ifmgd->assocresp_ies[i]); - } - } - len += sprintf(buf + len, ")"); - - if (len > IW_CUSTOM_MAX) { - len = sprintf(buf, "ASSOCRESPIE="); - for (i = 0; i < ifmgd->assocresp_ies_len; i++) { - len += sprintf(buf + len, "%02x", - ifmgd->assocresp_ies[i]); - } - } - - if (len <= IW_CUSTOM_MAX) { - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = len; - wireless_send_event(sdata->dev, IWEVCUSTOM, &wrqu, buf); - } - - kfree(buf); -} - - static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, u32 bss_info_changed) { @@ -966,7 +902,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, ifmgd->flags |= IEEE80211_STA_PREV_BSSID_SET; memcpy(ifmgd->prev_bssid, sdata->u.mgd.bssid, ETH_ALEN); - ieee80211_sta_send_associnfo(sdata); ifmgd->last_probe = jiffies; ieee80211_led_assoc(local, 1); @@ -993,8 +928,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, netif_tx_start_all_queues(sdata->dev); netif_carrier_on(sdata->dev); - - ieee80211_sta_send_apinfo(sdata); } static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata) @@ -1147,8 +1080,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, changed |= BSS_CHANGED_ASSOC; sdata->vif.bss_conf.assoc = false; - ieee80211_sta_send_apinfo(sdata); - if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) { ifmgd->state = IEEE80211_STA_MLME_DISABLED; ieee80211_rx_bss_remove(sdata, ifmgd->bssid, diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 1da81f456744..d4e61dc903e8 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -27,29 +27,6 @@ #include "aes_ccm.h" -static int ieee80211_ioctl_siwgenie(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - struct ieee80211_sub_if_data *sdata; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - int ret = ieee80211_sta_set_extra_ie(sdata, extra, data->length); - if (ret && ret != -EALREADY) - return ret; - sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; - sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME; - sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; - if (ret != -EALREADY) - ieee80211_sta_req_auth(sdata); - return 0; - } - - return -EOPNOTSUPP; -} - static int ieee80211_ioctl_siwfreq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra) @@ -61,16 +38,13 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev, if (sdata->vif.type == NL80211_IFTYPE_ADHOC) return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra); else if (sdata->vif.type == NL80211_IFTYPE_STATION) - sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL; + return cfg80211_mgd_wext_siwfreq(dev, info, freq, extra); /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */ if (freq->e == 0) { - if (freq->m < 0) { - if (sdata->vif.type == NL80211_IFTYPE_STATION) - sdata->u.mgd.flags |= - IEEE80211_STA_AUTO_CHANNEL_SEL; - return 0; - } else + if (freq->m < 0) + return -EINVAL; + else chan = ieee80211_get_channel(local->hw.wiphy, ieee80211_channel_to_frequency(freq->m)); } else { @@ -95,9 +69,6 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev, if (local->oper_channel == chan) return 0; - if (sdata->vif.type == NL80211_IFTYPE_STATION) - ieee80211_sta_req_auth(sdata); - local->oper_channel = chan; local->oper_channel_type = NL80211_CHAN_NO_HT; ieee80211_hw_config(local, 0); @@ -115,6 +86,8 @@ static int ieee80211_ioctl_giwfreq(struct net_device *dev, if (sdata->vif.type == NL80211_IFTYPE_ADHOC) return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); + else if (sdata->vif.type == NL80211_IFTYPE_STATION) + return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra); freq->m = local->oper_channel->center_freq; freq->e = 6; @@ -128,31 +101,11 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev, struct iw_point *data, char *ssid) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - size_t len = data->length; - int ret; if (sdata->vif.type == NL80211_IFTYPE_ADHOC) return cfg80211_ibss_wext_siwessid(dev, info, data, ssid); - - /* iwconfig uses nul termination in SSID.. */ - if (len > 0 && ssid[len - 1] == '\0') - len--; - - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - if (data->flags) - sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL; - else - sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL; - - ret = ieee80211_sta_set_ssid(sdata, ssid, len); - if (ret) - return ret; - - sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME; - sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; - ieee80211_sta_req_auth(sdata); - return 0; - } + else if (sdata->vif.type == NL80211_IFTYPE_STATION) + return cfg80211_mgd_wext_siwessid(dev, info, data, ssid); return -EOPNOTSUPP; } @@ -162,23 +115,14 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *ssid) { - size_t len; struct ieee80211_sub_if_data *sdata; sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->vif.type == NL80211_IFTYPE_ADHOC) return cfg80211_ibss_wext_giwessid(dev, info, data, ssid); - - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - int res = ieee80211_sta_get_ssid(sdata, ssid, &len); - if (res == 0) { - data->length = len; - data->flags = 1; - } else - data->flags = 0; - return res; - } + else if (sdata->vif.type == NL80211_IFTYPE_STATION) + return cfg80211_mgd_wext_giwessid(dev, info, data, ssid); return -EOPNOTSUPP; } @@ -193,24 +137,10 @@ static int ieee80211_ioctl_siwap(struct net_device *dev, if (sdata->vif.type == NL80211_IFTYPE_ADHOC) return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - int ret; + if (sdata->vif.type == NL80211_IFTYPE_STATION) + return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra); - if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) - sdata->u.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL | - IEEE80211_STA_AUTO_CHANNEL_SEL; - else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data)) - sdata->u.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL; - else - sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; - ret = ieee80211_sta_set_bssid(sdata, (u8 *) &ap_addr->sa_data); - if (ret) - return ret; - sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME; - sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; - ieee80211_sta_req_auth(sdata); - return 0; - } else if (sdata->vif.type == NL80211_IFTYPE_WDS) { + if (sdata->vif.type == NL80211_IFTYPE_WDS) { /* * If it is necessary to update the WDS peer address * while the interface is running, then we need to do @@ -240,14 +170,10 @@ static int ieee80211_ioctl_giwap(struct net_device *dev, if (sdata->vif.type == NL80211_IFTYPE_ADHOC) return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra); - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - if (sdata->u.mgd.state == IEEE80211_STA_MLME_ASSOCIATED) { - ap_addr->sa_family = ARPHRD_ETHER; - memcpy(&ap_addr->sa_data, sdata->u.mgd.bssid, ETH_ALEN); - } else - memset(&ap_addr->sa_data, 0, ETH_ALEN); - return 0; - } else if (sdata->vif.type == NL80211_IFTYPE_WDS) { + if (sdata->vif.type == NL80211_IFTYPE_STATION) + return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra); + + if (sdata->vif.type == NL80211_IFTYPE_WDS) { ap_addr->sa_family = ARPHRD_ETHER; memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN); return 0; @@ -395,85 +321,6 @@ static int ieee80211_ioctl_giwpower(struct net_device *dev, return 0; } -static int ieee80211_ioctl_siwauth(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *data, char *extra) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - int ret = 0; - - switch (data->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_WPA_ENABLED: - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - case IW_AUTH_KEY_MGMT: - case IW_AUTH_CIPHER_GROUP_MGMT: - break; - case IW_AUTH_CIPHER_PAIRWISE: - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - if (data->value & (IW_AUTH_CIPHER_WEP40 | - IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_TKIP)) - sdata->u.mgd.flags |= - IEEE80211_STA_TKIP_WEP_USED; - else - sdata->u.mgd.flags &= - ~IEEE80211_STA_TKIP_WEP_USED; - } - break; - case IW_AUTH_DROP_UNENCRYPTED: - sdata->drop_unencrypted = !!data->value; - break; - case IW_AUTH_PRIVACY_INVOKED: - if (sdata->vif.type != NL80211_IFTYPE_STATION) - ret = -EINVAL; - else { - sdata->u.mgd.flags &= ~IEEE80211_STA_PRIVACY_INVOKED; - /* - * Privacy invoked by wpa_supplicant, store the - * value and allow associating to a protected - * network without having a key up front. - */ - if (data->value) - sdata->u.mgd.flags |= - IEEE80211_STA_PRIVACY_INVOKED; - } - break; - case IW_AUTH_80211_AUTH_ALG: - if (sdata->vif.type == NL80211_IFTYPE_STATION) - sdata->u.mgd.auth_algs = data->value; - else - ret = -EOPNOTSUPP; - break; - case IW_AUTH_MFP: - if (!(sdata->local->hw.flags & IEEE80211_HW_MFP_CAPABLE)) { - ret = -EOPNOTSUPP; - break; - } - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - switch (data->value) { - case IW_AUTH_MFP_DISABLED: - sdata->u.mgd.mfp = IEEE80211_MFP_DISABLED; - break; - case IW_AUTH_MFP_OPTIONAL: - sdata->u.mgd.mfp = IEEE80211_MFP_OPTIONAL; - break; - case IW_AUTH_MFP_REQUIRED: - sdata->u.mgd.mfp = IEEE80211_MFP_REQUIRED; - break; - default: - ret = -EINVAL; - } - } else - ret = -EOPNOTSUPP; - break; - default: - ret = -EOPNOTSUPP; - break; - } - return ret; -} - /* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev) { @@ -541,28 +388,6 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev return wstats; } -static int ieee80211_ioctl_giwauth(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *data, char *extra) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - int ret = 0; - - switch (data->flags & IW_AUTH_INDEX) { - case IW_AUTH_80211_AUTH_ALG: - if (sdata->vif.type == NL80211_IFTYPE_STATION) - data->value = sdata->u.mgd.auth_algs; - else - ret = -EOPNOTSUPP; - break; - default: - ret = -EOPNOTSUPP; - break; - } - return ret; -} - - /* Structures to export the Wireless Handlers */ static const iw_handler ieee80211_handler[] = @@ -615,10 +440,10 @@ static const iw_handler ieee80211_handler[] = (iw_handler) ieee80211_ioctl_giwpower, /* SIOCGIWPOWER */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* -- hole -- */ - (iw_handler) ieee80211_ioctl_siwgenie, /* SIOCSIWGENIE */ + (iw_handler) cfg80211_wext_siwgenie, /* SIOCSIWGENIE */ (iw_handler) NULL, /* SIOCGIWGENIE */ - (iw_handler) ieee80211_ioctl_siwauth, /* SIOCSIWAUTH */ - (iw_handler) ieee80211_ioctl_giwauth, /* SIOCGIWAUTH */ + (iw_handler) cfg80211_wext_siwauth, /* SIOCSIWAUTH */ + (iw_handler) cfg80211_wext_giwauth, /* SIOCGIWAUTH */ (iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */ (iw_handler) NULL, /* SIOCGIWENCODEEXT */ (iw_handler) NULL, /* SIOCSIWPMKSA */ -- cgit v1.2.3 From bc92afd92088ab41223383cc6863ab4792533c54 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:26:57 +0200 Subject: cfg80211: implement iwpower Just on/off and timeout, and with a hacky cfg80211 method until we figure out what we want, though this is probably sufficient as we want to use pm_qos for wifi everywhere. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/Kconfig | 16 ------------ net/mac80211/cfg.c | 26 +++++++++++++++++++ net/mac80211/mlme.c | 5 ---- net/mac80211/wext.c | 70 ++-------------------------------------------------- 4 files changed, 28 insertions(+), 89 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index ba2643a43c73..41a32cd919af 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -14,22 +14,6 @@ config MAC80211 comment "CFG80211 needs to be enabled for MAC80211" depends on CFG80211=n -config MAC80211_DEFAULT_PS - bool "enable powersave by default" - depends on MAC80211 - default y - help - This option enables powersave mode by default. - - If this causes your applications to misbehave you should fix your - applications instead -- they need to register their network - latency requirement, see Documentation/power/pm_qos_interface.txt. - -config MAC80211_DEFAULT_PS_VALUE - int - default 1 if MAC80211_DEFAULT_PS - default 0 - menu "Rate control algorithm selection" depends on MAC80211 != n diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 03de4024597a..8c7b2cdbeeda 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1388,6 +1388,31 @@ int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len) } #endif +static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, + bool enabled, int timeout) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_conf *conf = &local->hw.conf; + + if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) + return -EOPNOTSUPP; + + if (enabled == sdata->u.mgd.powersave && + timeout == conf->dynamic_ps_timeout) + return 0; + + sdata->u.mgd.powersave = enabled; + conf->dynamic_ps_timeout = timeout; + + if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); + + ieee80211_recalc_ps(local, -1); + + return 0; +} + struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, @@ -1431,4 +1456,5 @@ struct cfg80211_ops mac80211_config_ops = { .get_tx_power = ieee80211_get_tx_power, .rfkill_poll = ieee80211_rfkill_poll, CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) + .set_power_mgmt = ieee80211_set_power_mgmt, }; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index fbb93a70ddc7..2a7860009f9c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2360,11 +2360,6 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) ifmgd->flags |= IEEE80211_STA_WMM_ENABLED; hw_flags = sdata->local->hw.flags; - - if (hw_flags & IEEE80211_HW_SUPPORTS_PS) { - ifmgd->powersave = CONFIG_MAC80211_DEFAULT_PS_VALUE; - sdata->local->hw.conf.dynamic_ps_timeout = 500; - } } /* configuration hooks */ diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index d4e61dc903e8..f77929802c7a 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -255,72 +255,6 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev, return 0; } -static int ieee80211_ioctl_siwpower(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *wrq, - char *extra) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_conf *conf = &local->hw.conf; - int timeout = 0; - bool ps; - - if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) - return -EOPNOTSUPP; - - if (sdata->vif.type != NL80211_IFTYPE_STATION) - return -EINVAL; - - if (wrq->disabled) { - ps = false; - timeout = 0; - goto set; - } - - switch (wrq->flags & IW_POWER_MODE) { - case IW_POWER_ON: /* If not specified */ - case IW_POWER_MODE: /* If set all mask */ - case IW_POWER_ALL_R: /* If explicitely state all */ - ps = true; - break; - default: /* Otherwise we ignore */ - return -EINVAL; - } - - if (wrq->flags & ~(IW_POWER_MODE | IW_POWER_TIMEOUT)) - return -EINVAL; - - if (wrq->flags & IW_POWER_TIMEOUT) - timeout = wrq->value / 1000; - - set: - if (ps == sdata->u.mgd.powersave && timeout == conf->dynamic_ps_timeout) - return 0; - - sdata->u.mgd.powersave = ps; - conf->dynamic_ps_timeout = timeout; - - if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); - - ieee80211_recalc_ps(local, -1); - - return 0; -} - -static int ieee80211_ioctl_giwpower(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - wrqu->power.disabled = !sdata->u.mgd.powersave; - - return 0; -} - /* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev) { @@ -436,8 +370,8 @@ static const iw_handler ieee80211_handler[] = (iw_handler) cfg80211_wext_giwretry, /* SIOCGIWRETRY */ (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */ (iw_handler) cfg80211_wext_giwencode, /* SIOCGIWENCODE */ - (iw_handler) ieee80211_ioctl_siwpower, /* SIOCSIWPOWER */ - (iw_handler) ieee80211_ioctl_giwpower, /* SIOCGIWPOWER */ + (iw_handler) cfg80211_wext_siwpower, /* SIOCSIWPOWER */ + (iw_handler) cfg80211_wext_giwpower, /* SIOCGIWPOWER */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) cfg80211_wext_siwgenie, /* SIOCSIWGENIE */ -- cgit v1.2.3 From ab737a4f7dbe57b12b73f482a7b973bf00b41942 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:26:58 +0200 Subject: cfg80211: implement IWAP for WDS This implements siocsiwap/giwap for WDS mode. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 11 +++++++++++ net/mac80211/wext.c | 26 ++++---------------------- 2 files changed, 15 insertions(+), 22 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 8c7b2cdbeeda..2cf5bf6378e4 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1369,6 +1369,16 @@ static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm) return 0; } +static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev, + u8 *addr) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + memcpy(&sdata->u.wds.remote_addr, addr, ETH_ALEN); + + return 0; +} + static void ieee80211_rfkill_poll(struct wiphy *wiphy) { struct ieee80211_local *local = wiphy_priv(wiphy); @@ -1454,6 +1464,7 @@ struct cfg80211_ops mac80211_config_ops = { .set_wiphy_params = ieee80211_set_wiphy_params, .set_tx_power = ieee80211_set_tx_power, .get_tx_power = ieee80211_get_tx_power, + .set_wds_peer = ieee80211_set_wds_peer, .rfkill_poll = ieee80211_rfkill_poll, CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) .set_power_mgmt = ieee80211_set_power_mgmt, diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index f77929802c7a..4053d766af2d 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -140,23 +140,8 @@ static int ieee80211_ioctl_siwap(struct net_device *dev, if (sdata->vif.type == NL80211_IFTYPE_STATION) return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra); - if (sdata->vif.type == NL80211_IFTYPE_WDS) { - /* - * If it is necessary to update the WDS peer address - * while the interface is running, then we need to do - * more work here, namely if it is running we need to - * add a new and remove the old STA entry, this is - * normally handled by _open() and _stop(). - */ - if (netif_running(dev)) - return -EBUSY; - - memcpy(&sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data, - ETH_ALEN); - - return 0; - } - + if (sdata->vif.type == NL80211_IFTYPE_WDS) + return cfg80211_wds_wext_siwap(dev, info, ap_addr, extra); return -EOPNOTSUPP; } @@ -173,11 +158,8 @@ static int ieee80211_ioctl_giwap(struct net_device *dev, if (sdata->vif.type == NL80211_IFTYPE_STATION) return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra); - if (sdata->vif.type == NL80211_IFTYPE_WDS) { - ap_addr->sa_family = ARPHRD_ETHER; - memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN); - return 0; - } + if (sdata->vif.type == NL80211_IFTYPE_WDS) + return cfg80211_wds_wext_giwap(dev, info, ap_addr, extra); return -EOPNOTSUPP; } -- cgit v1.2.3 From 9930380f0bd8405fa6a51d644f3de88c30666519 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:26:59 +0200 Subject: cfg80211: implement IWRATE For now, let's implement that using a very hackish way: simply mirror the wext API in the cfg80211 API. This will have to be changed later when we implement proper bitrate API. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 43 ++++++++++++++++++++++++++++++ net/mac80211/wext.c | 76 ++--------------------------------------------------- 2 files changed, 45 insertions(+), 74 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 2cf5bf6378e4..028f6430879d 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1423,6 +1423,48 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, return 0; } +static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, + struct net_device *dev, + const u8 *addr, + const struct cfg80211_bitrate_mask *mask) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + int i, err = -EINVAL; + u32 target_rate; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates + * target_rate = X, rate->fixed = 1 means only rate X + * target_rate = X, rate->fixed = 0 means all rates <= X */ + sdata->max_ratectrl_rateidx = -1; + sdata->force_unicast_rateidx = -1; + + if (mask->fixed) + target_rate = mask->fixed / 100; + else if (mask->maxrate) + target_rate = mask->maxrate / 100; + else + return 0; + + for (i=0; i< sband->n_bitrates; i++) { + struct ieee80211_rate *brate = &sband->bitrates[i]; + int this_rate = brate->bitrate; + + if (target_rate == this_rate) { + sdata->max_ratectrl_rateidx = i; + if (mask->fixed) + sdata->force_unicast_rateidx = i; + err = 0; + break; + } + } + + return err; +} + struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, @@ -1468,4 +1510,5 @@ struct cfg80211_ops mac80211_config_ops = { .rfkill_poll = ieee80211_rfkill_poll, CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) .set_power_mgmt = ieee80211_set_power_mgmt, + .set_bitrate_mask = ieee80211_set_bitrate_mask, }; diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 4053d766af2d..244d830f5cfb 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -165,78 +165,6 @@ static int ieee80211_ioctl_giwap(struct net_device *dev, } -static int ieee80211_ioctl_siwrate(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *rate, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - int i, err = -EINVAL; - u32 target_rate = rate->value / 100000; - struct ieee80211_sub_if_data *sdata; - struct ieee80211_supported_band *sband; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - - /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates - * target_rate = X, rate->fixed = 1 means only rate X - * target_rate = X, rate->fixed = 0 means all rates <= X */ - sdata->max_ratectrl_rateidx = -1; - sdata->force_unicast_rateidx = -1; - if (rate->value < 0) - return 0; - - for (i=0; i< sband->n_bitrates; i++) { - struct ieee80211_rate *brate = &sband->bitrates[i]; - int this_rate = brate->bitrate; - - if (target_rate == this_rate) { - sdata->max_ratectrl_rateidx = i; - if (rate->fixed) - sdata->force_unicast_rateidx = i; - err = 0; - break; - } - } - return err; -} - -static int ieee80211_ioctl_giwrate(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *rate, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct sta_info *sta; - struct ieee80211_sub_if_data *sdata; - struct ieee80211_supported_band *sband; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (sdata->vif.type != NL80211_IFTYPE_STATION) - return -EOPNOTSUPP; - - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - - rcu_read_lock(); - - sta = sta_info_get(local, sdata->u.mgd.bssid); - - if (sta && !(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)) - rate->value = sband->bitrates[sta->last_tx_rate.idx].bitrate; - else - rate->value = 0; - - rcu_read_unlock(); - - if (!sta) - return -ENODEV; - - rate->value *= 100000; - - return 0; -} - /* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev) { @@ -340,8 +268,8 @@ static const iw_handler ieee80211_handler[] = (iw_handler) NULL, /* SIOCGIWNICKN */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* -- hole -- */ - (iw_handler) ieee80211_ioctl_siwrate, /* SIOCSIWRATE */ - (iw_handler) ieee80211_ioctl_giwrate, /* SIOCGIWRATE */ + (iw_handler) cfg80211_wext_siwrate, /* SIOCSIWRATE */ + (iw_handler) cfg80211_wext_giwrate, /* SIOCGIWRATE */ (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */ (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */ (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */ -- cgit v1.2.3 From 8990646d2fafeacfacba4a4b1073a4216662089a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:27:00 +0200 Subject: cfg80211: implement get_wireless_stats By dropping the noise reporting, we can implement wireless stats in cfg80211. We also make the handler return NULL if we have no information, which is possible thanks to the recent wext change. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/wext.c | 69 +---------------------------------------------------- 1 file changed, 1 insertion(+), 68 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 244d830f5cfb..5acb8140ee58 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -165,73 +165,6 @@ static int ieee80211_ioctl_giwap(struct net_device *dev, } -/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ -static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct iw_statistics *wstats = &local->wstats; - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct sta_info *sta = NULL; - - rcu_read_lock(); - - if (sdata->vif.type == NL80211_IFTYPE_STATION) - sta = sta_info_get(local, sdata->u.mgd.bssid); - - if (!sta) { - wstats->discard.fragment = 0; - wstats->discard.misc = 0; - wstats->qual.qual = 0; - wstats->qual.level = 0; - wstats->qual.noise = 0; - wstats->qual.updated = IW_QUAL_ALL_INVALID; - } else { - wstats->qual.updated = 0; - /* - * mirror what cfg80211 does for iwrange/scan results, - * otherwise userspace gets confused. - */ - if (local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC | - IEEE80211_HW_SIGNAL_DBM)) { - wstats->qual.updated |= IW_QUAL_LEVEL_UPDATED; - wstats->qual.updated |= IW_QUAL_QUAL_UPDATED; - } else { - wstats->qual.updated |= IW_QUAL_LEVEL_INVALID; - wstats->qual.updated |= IW_QUAL_QUAL_INVALID; - } - - if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) { - wstats->qual.level = sta->last_signal; - wstats->qual.qual = sta->last_signal; - } else if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) { - int sig = sta->last_signal; - - wstats->qual.updated |= IW_QUAL_DBM; - wstats->qual.level = sig; - if (sig < -110) - sig = -110; - else if (sig > -40) - sig = -40; - wstats->qual.qual = sig + 110; - } - - if (local->hw.flags & IEEE80211_HW_NOISE_DBM) { - /* - * This assumes that if driver reports noise, it also - * reports signal in dBm. - */ - wstats->qual.noise = sta->last_noise; - wstats->qual.updated |= IW_QUAL_NOISE_UPDATED; - } else { - wstats->qual.updated |= IW_QUAL_NOISE_INVALID; - } - } - - rcu_read_unlock(); - - return wstats; -} - /* Structures to export the Wireless Handlers */ static const iw_handler ieee80211_handler[] = @@ -298,5 +231,5 @@ const struct iw_handler_def ieee80211_iw_handler_def = { .num_standard = ARRAY_SIZE(ieee80211_handler), .standard = (iw_handler *) ieee80211_handler, - .get_wireless_stats = ieee80211_get_wireless_stats, + .get_wireless_stats = cfg80211_wireless_stats, }; -- cgit v1.2.3 From ac00326e9d1d46bf48e9cf60cf892a96b885601a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:27:01 +0200 Subject: mac80211: re-add HT disabling The IEEE80211_STA_TKIP_WEP_USED flag is used internally to disable HT when WEP or TKIP are used. Now that cfg80211 is giving us the required information, we can set the flag appropriately again. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 028f6430879d..af4733ba5be2 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1228,7 +1228,7 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_assoc_request *req) { struct ieee80211_sub_if_data *sdata; - int ret; + int ret, i; sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -1236,6 +1236,14 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, !(sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED)) return -ENOLINK; /* not authenticated */ + sdata->u.mgd.flags &= ~IEEE80211_STA_TKIP_WEP_USED; + + for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) + if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || + req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || + req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) + sdata->u.mgd.flags |= IEEE80211_STA_TKIP_WEP_USED; + sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; sdata->u.mgd.flags |= IEEE80211_STA_BSSID_SET; -- cgit v1.2.3 From 6dc1cb0319997648f59b0f46b9e093e779f0353d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:40:45 +0200 Subject: mac80211: remove auth algorithm retry The automatic auth algorithm issue is now solved in cfg80211, so mac80211 no longer needs code to try different algorithms -- just using whatever cfg80211 asked for is good. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 8 ++++---- net/mac80211/debugfs_netdev.c | 3 --- net/mac80211/ieee80211_i.h | 8 -------- net/mac80211/mlme.c | 47 ------------------------------------------- 4 files changed, 4 insertions(+), 62 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index af4733ba5be2..3c9774e36a80 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1178,16 +1178,16 @@ static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, switch (req->auth_type) { case NL80211_AUTHTYPE_OPEN_SYSTEM: - sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_OPEN; + sdata->u.mgd.auth_alg = WLAN_AUTH_OPEN; break; case NL80211_AUTHTYPE_SHARED_KEY: - sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_SHARED_KEY; + sdata->u.mgd.auth_alg = WLAN_AUTH_SHARED_KEY; break; case NL80211_AUTHTYPE_FT: - sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_FT; + sdata->u.mgd.auth_alg = WLAN_AUTH_FT; break; case NL80211_AUTHTYPE_NETWORK_EAP: - sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_LEAP; + sdata->u.mgd.auth_alg = WLAN_AUTH_LEAP; break; default: return -EOPNOTSUPP; diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index e3420329f4e6..df8c804e2d9a 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -105,7 +105,6 @@ IEEE80211_IF_FILE(capab, u.mgd.capab, HEX); IEEE80211_IF_FILE(extra_ie_len, u.mgd.extra_ie_len, SIZE); IEEE80211_IF_FILE(auth_tries, u.mgd.auth_tries, DEC); IEEE80211_IF_FILE(assoc_tries, u.mgd.assoc_tries, DEC); -IEEE80211_IF_FILE(auth_algs, u.mgd.auth_algs, HEX); IEEE80211_IF_FILE(auth_alg, u.mgd.auth_alg, DEC); IEEE80211_IF_FILE(auth_transaction, u.mgd.auth_transaction, DEC); @@ -194,7 +193,6 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_ADD(extra_ie_len, sta); DEBUGFS_ADD(auth_tries, sta); DEBUGFS_ADD(assoc_tries, sta); - DEBUGFS_ADD(auth_algs, sta); DEBUGFS_ADD(auth_alg, sta); DEBUGFS_ADD(auth_transaction, sta); DEBUGFS_ADD(flags, sta); @@ -327,7 +325,6 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_DEL(extra_ie_len, sta); DEBUGFS_DEL(auth_tries, sta); DEBUGFS_DEL(assoc_tries, sta); - DEBUGFS_DEL(auth_algs, sta); DEBUGFS_DEL(auth_alg, sta); DEBUGFS_DEL(auth_transaction, sta); DEBUGFS_DEL(flags, sta); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 1950e2eb4150..f7024eeba8f5 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -251,12 +251,6 @@ struct mesh_preq_queue { #define IEEE80211_STA_REQ_AUTH 1 #define IEEE80211_STA_REQ_RUN 2 -/* bitfield of allowed auth algs */ -#define IEEE80211_AUTH_ALG_OPEN BIT(0) -#define IEEE80211_AUTH_ALG_SHARED_KEY BIT(1) -#define IEEE80211_AUTH_ALG_LEAP BIT(2) -#define IEEE80211_AUTH_ALG_FT BIT(3) - struct ieee80211_if_managed { struct timer_list timer; struct timer_list chswitch_timer; @@ -303,7 +297,6 @@ struct ieee80211_if_managed { unsigned int flags; - unsigned int auth_algs; /* bitfield of allowed auth algs */ int auth_alg; /* currently used IEEE 802.11 authentication algorithm */ int auth_transaction; @@ -488,7 +481,6 @@ struct ieee80211_sub_if_data { struct dentry *extra_ie_len; struct dentry *auth_tries; struct dentry *assoc_tries; - struct dentry *auth_algs; struct dentry *auth_alg; struct dentry *auth_transaction; struct dentry *flags; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2a7860009f9c..2b357c7adb8d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1414,39 +1414,6 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, return; if (status_code != WLAN_STATUS_SUCCESS) { - if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) { - u8 algs[3]; - const int num_algs = ARRAY_SIZE(algs); - int i, pos; - algs[0] = algs[1] = algs[2] = 0xff; - if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_OPEN) - algs[0] = WLAN_AUTH_OPEN; - if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY) - algs[1] = WLAN_AUTH_SHARED_KEY; - if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_LEAP) - algs[2] = WLAN_AUTH_LEAP; - if (ifmgd->auth_alg == WLAN_AUTH_OPEN) - pos = 0; - else if (ifmgd->auth_alg == WLAN_AUTH_SHARED_KEY) - pos = 1; - else - pos = 2; - for (i = 0; i < num_algs; i++) { - pos++; - if (pos >= num_algs) - pos = 0; - if (algs[pos] == ifmgd->auth_alg || - algs[pos] == 0xff) - continue; - if (algs[pos] == WLAN_AUTH_SHARED_KEY && - !ieee80211_sta_wep_configured(sdata)) - continue; - ifmgd->auth_alg = algs[pos]; - ifmgd->auth_tries = 0; - return; - } - } - /* nothing else to try -- give up */ cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len, GFP_KERNEL); ifmgd->state = IEEE80211_STA_MLME_DISABLED; @@ -2102,18 +2069,6 @@ static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata) drv_reset_tsf(local); ifmgd->wmm_last_param_set = -1; /* allow any WMM update */ - - - if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_OPEN) - ifmgd->auth_alg = WLAN_AUTH_OPEN; - else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY) - ifmgd->auth_alg = WLAN_AUTH_SHARED_KEY; - else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_LEAP) - ifmgd->auth_alg = WLAN_AUTH_LEAP; - else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_FT) - ifmgd->auth_alg = WLAN_AUTH_FT; - else - ifmgd->auth_alg = WLAN_AUTH_OPEN; ifmgd->auth_transaction = -1; ifmgd->flags &= ~IEEE80211_STA_ASSOCIATED; ifmgd->assoc_scan_tries = 0; @@ -2351,8 +2306,6 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) skb_queue_head_init(&ifmgd->skb_queue); ifmgd->capab = WLAN_CAPABILITY_ESS; - ifmgd->auth_algs = IEEE80211_AUTH_ALG_OPEN | - IEEE80211_AUTH_ALG_SHARED_KEY; ifmgd->flags |= IEEE80211_STA_CREATE_IBSS | IEEE80211_STA_AUTO_BSSID_SEL | IEEE80211_STA_AUTO_CHANNEL_SEL; -- cgit v1.2.3 From ab1faead50d09165b58c2854997c7205ca9c0d22 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Jul 2009 21:41:17 +0200 Subject: mac80211: remove dead code, clean up With mac80211 now always controlled by an external SME, a lot of code is dead -- SSID, BSSID, channel selection is always done externally, etc. Additionally, rename IEEE80211_STA_TKIP_WEP_USED to IEEE80211_STA_DISABLE_11N and clean up the code a bit. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 39 +++---- net/mac80211/debugfs_netdev.c | 4 +- net/mac80211/ieee80211_i.h | 42 ++++---- net/mac80211/iface.c | 2 - net/mac80211/mlme.c | 231 ++++-------------------------------------- 5 files changed, 54 insertions(+), 264 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 3c9774e36a80..7606571d4581 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1194,18 +1194,14 @@ static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, } memcpy(sdata->u.mgd.bssid, req->peer_addr, ETH_ALEN); - sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; - sdata->u.mgd.flags |= IEEE80211_STA_BSSID_SET; - /* TODO: req->chan */ - sdata->u.mgd.flags |= IEEE80211_STA_AUTO_CHANNEL_SEL; + sdata->local->oper_channel = req->chan; + ieee80211_hw_config(sdata->local, 0); - if (req->ssid) { - sdata->u.mgd.flags |= IEEE80211_STA_SSID_SET; - memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len); - sdata->u.mgd.ssid_len = req->ssid_len; - sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL; - } + if (!req->ssid) + return -EINVAL; + memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len); + sdata->u.mgd.ssid_len = req->ssid_len; kfree(sdata->u.mgd.sme_auth_ie); sdata->u.mgd.sme_auth_ie = NULL; @@ -1218,7 +1214,6 @@ static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, sdata->u.mgd.sme_auth_ie_len = req->ie_len; } - sdata->u.mgd.flags |= IEEE80211_STA_EXT_SME; sdata->u.mgd.state = IEEE80211_STA_MLME_DIRECT_PROBE; ieee80211_sta_req_auth(sdata); return 0; @@ -1236,27 +1231,22 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, !(sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED)) return -ENOLINK; /* not authenticated */ - sdata->u.mgd.flags &= ~IEEE80211_STA_TKIP_WEP_USED; + sdata->u.mgd.flags &= ~IEEE80211_STA_DISABLE_11N; for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) - sdata->u.mgd.flags |= IEEE80211_STA_TKIP_WEP_USED; + sdata->u.mgd.flags |= IEEE80211_STA_DISABLE_11N; - sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; - sdata->u.mgd.flags |= IEEE80211_STA_BSSID_SET; + sdata->local->oper_channel = req->chan; + ieee80211_hw_config(sdata->local, 0); - /* TODO: req->chan */ - sdata->u.mgd.flags |= IEEE80211_STA_AUTO_CHANNEL_SEL; + if (!req->ssid) + return -EINVAL; - if (req->ssid) { - sdata->u.mgd.flags |= IEEE80211_STA_SSID_SET; - memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len); - sdata->u.mgd.ssid_len = req->ssid_len; - sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL; - } else - sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL; + memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len); + sdata->u.mgd.ssid_len = req->ssid_len; ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len); if (ret && ret != -EALREADY) @@ -1275,7 +1265,6 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, else sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; - sdata->u.mgd.flags |= IEEE80211_STA_EXT_SME; sdata->u.mgd.state = IEEE80211_STA_MLME_ASSOCIATE; ieee80211_sta_req_auth(sdata); return 0; diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index df8c804e2d9a..ffe9add3ef42 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -111,9 +111,7 @@ IEEE80211_IF_FILE(auth_transaction, u.mgd.auth_transaction, DEC); static ssize_t ieee80211_if_fmt_flags( const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) { - return scnprintf(buf, buflen, "%s%s%s%s%s%s%s\n", - sdata->u.mgd.flags & IEEE80211_STA_SSID_SET ? "SSID\n" : "", - sdata->u.mgd.flags & IEEE80211_STA_BSSID_SET ? "BSSID\n" : "", + return scnprintf(buf, buflen, "%s%s%s%s%s\n", sdata->u.mgd.flags & IEEE80211_STA_PREV_BSSID_SET ? "prev BSSID\n" : "", sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "", sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "", diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index f7024eeba8f5..a550aeb85053 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -228,28 +228,24 @@ struct mesh_preq_queue { }; /* flags used in struct ieee80211_if_managed.flags */ -#define IEEE80211_STA_SSID_SET BIT(0) -#define IEEE80211_STA_BSSID_SET BIT(1) -#define IEEE80211_STA_PREV_BSSID_SET BIT(2) -#define IEEE80211_STA_AUTHENTICATED BIT(3) -#define IEEE80211_STA_ASSOCIATED BIT(4) -#define IEEE80211_STA_PROBEREQ_POLL BIT(5) -#define IEEE80211_STA_CREATE_IBSS BIT(6) -#define IEEE80211_STA_CONTROL_PORT BIT(7) -#define IEEE80211_STA_WMM_ENABLED BIT(8) -/* hole at 9, please re-use */ -#define IEEE80211_STA_AUTO_SSID_SEL BIT(10) -#define IEEE80211_STA_AUTO_BSSID_SEL BIT(11) -#define IEEE80211_STA_AUTO_CHANNEL_SEL BIT(12) -#define IEEE80211_STA_PRIVACY_INVOKED BIT(13) -#define IEEE80211_STA_TKIP_WEP_USED BIT(14) -#define IEEE80211_STA_CSA_RECEIVED BIT(15) -#define IEEE80211_STA_MFP_ENABLED BIT(16) -#define IEEE80211_STA_EXT_SME BIT(17) +enum ieee80211_sta_flags { + IEEE80211_STA_PREV_BSSID_SET = BIT(0), + IEEE80211_STA_AUTHENTICATED = BIT(1), + IEEE80211_STA_ASSOCIATED = BIT(2), + IEEE80211_STA_PROBEREQ_POLL = BIT(3), + IEEE80211_STA_CONTROL_PORT = BIT(4), + IEEE80211_STA_WMM_ENABLED = BIT(5), + IEEE80211_STA_DISABLE_11N = BIT(6), + IEEE80211_STA_CSA_RECEIVED = BIT(7), + IEEE80211_STA_MFP_ENABLED = BIT(8), +}; + /* flags for MLME request */ -#define IEEE80211_STA_REQ_SCAN 0 -#define IEEE80211_STA_REQ_AUTH 1 -#define IEEE80211_STA_REQ_RUN 2 +enum ieee80211_sta_request { + IEEE80211_STA_REQ_SCAN, + IEEE80211_STA_REQ_AUTH, + IEEE80211_STA_REQ_RUN, +}; struct ieee80211_if_managed { struct timer_list timer; @@ -936,10 +932,6 @@ extern const struct iw_handler_def ieee80211_iw_handler_def; void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata); ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); -int ieee80211_sta_commit(struct ieee80211_sub_if_data *sdata); -int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len); -int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len); -int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid); void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata); int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason); int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index b7c8a4484298..b87bf425f857 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -486,8 +486,6 @@ static int ieee80211_stop(struct net_device *dev) synchronize_rcu(); skb_queue_purge(&sdata->u.mgd.skb_queue); - sdata->u.mgd.flags &= ~(IEEE80211_STA_PRIVACY_INVOKED | - IEEE80211_STA_TKIP_WEP_USED); kfree(sdata->u.mgd.extra_ie); sdata->u.mgd.extra_ie = NULL; sdata->u.mgd.extra_ie_len = 0; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2b357c7adb8d..2d9b6663253c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -347,7 +347,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) sband->ht_cap.ht_supported && (ht_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_INFORMATION)) && ht_ie[1] >= sizeof(struct ieee80211_ht_info) && - (!(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED))) { + (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))) { struct ieee80211_ht_info *ht_info = (struct ieee80211_ht_info *)(ht_ie + 2); u16 cap = sband->ht_cap.cap; @@ -981,8 +981,6 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; - u8 *ies; - size_t ies_len; ifmgd->auth_tries++; if (ifmgd->auth_tries > IEEE80211_AUTH_MAX_TRIES) { @@ -1010,15 +1008,8 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata) printk(KERN_DEBUG "%s: authenticate with AP %pM\n", sdata->dev->name, ifmgd->bssid); - if (ifmgd->flags & IEEE80211_STA_EXT_SME) { - ies = ifmgd->sme_auth_ie; - ies_len = ifmgd->sme_auth_ie_len; - } else { - ies = NULL; - ies_len = 0; - } - ieee80211_send_auth(sdata, 1, ifmgd->auth_alg, ies, ies_len, - ifmgd->bssid, 0); + ieee80211_send_auth(sdata, 1, ifmgd->auth_alg, ifmgd->sme_auth_ie, + ifmgd->sme_auth_ie_len, ifmgd->bssid, 0); ifmgd->auth_transaction = 2; mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT); @@ -1128,44 +1119,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, sta_info_destroy(sta); } -static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata) -{ - if (!sdata || !sdata->default_key || - sdata->default_key->conf.alg != ALG_WEP) - return 0; - return 1; -} - -static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata) -{ - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_local *local = sdata->local; - struct ieee80211_bss *bss; - int bss_privacy; - int wep_privacy; - int privacy_invoked; - - if (!ifmgd || (ifmgd->flags & IEEE80211_STA_EXT_SME)) - return 0; - - bss = ieee80211_rx_bss_get(local, ifmgd->bssid, - local->hw.conf.channel->center_freq, - ifmgd->ssid, ifmgd->ssid_len); - if (!bss) - return 0; - - bss_privacy = !!(bss->cbss.capability & WLAN_CAPABILITY_PRIVACY); - wep_privacy = !!ieee80211_sta_wep_configured(sdata); - privacy_invoked = !!(ifmgd->flags & IEEE80211_STA_PRIVACY_INVOKED); - - ieee80211_rx_bss_put(local, bss); - - if ((bss_privacy == wep_privacy) || (bss_privacy == privacy_invoked)) - return 0; - - return 1; -} - static void ieee80211_associate(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; @@ -1195,14 +1148,6 @@ static void ieee80211_associate(struct ieee80211_sub_if_data *sdata) ifmgd->state = IEEE80211_STA_MLME_ASSOCIATE; printk(KERN_DEBUG "%s: associate with AP %pM\n", sdata->dev->name, ifmgd->bssid); - if (ieee80211_privacy_mismatch(sdata)) { - printk(KERN_DEBUG "%s: mismatch in privacy configuration and " - "mixed-cell disabled - abort association\n", sdata->dev->name); - ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_recalc_idle(local); - return; - } - ieee80211_send_assoc(sdata); mod_timer(&ifmgd->timer, jiffies + IEEE80211_ASSOC_TIMEOUT); @@ -1360,12 +1305,9 @@ static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata) printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name); ifmgd->flags |= IEEE80211_STA_AUTHENTICATED; - if (ifmgd->flags & IEEE80211_STA_EXT_SME) { - /* Wait for SME to request association */ - ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_recalc_idle(sdata->local); - } else - ieee80211_associate(sdata); + /* Wait for SME to request association */ + ifmgd->state = IEEE80211_STA_MLME_DISABLED; + ieee80211_recalc_idle(sdata->local); } @@ -1460,15 +1402,6 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n", sdata->dev->name, reason_code); - if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) && - (ifmgd->state == IEEE80211_STA_MLME_AUTHENTICATE || - ifmgd->state == IEEE80211_STA_MLME_ASSOCIATE || - ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED)) { - ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE; - mod_timer(&ifmgd->timer, jiffies + - IEEE80211_RETRY_AUTH_INTERVAL); - } - ieee80211_set_disassoc(sdata, true, false, 0); ifmgd->flags &= ~IEEE80211_STA_AUTHENTICATED; cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, len, GFP_KERNEL); @@ -1494,13 +1427,6 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", sdata->dev->name, reason_code); - if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) && - ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) { - ifmgd->state = IEEE80211_STA_MLME_ASSOCIATE; - mod_timer(&ifmgd->timer, jiffies + - IEEE80211_RETRY_AUTH_INTERVAL); - } - ieee80211_set_disassoc(sdata, false, false, reason_code); cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, len, GFP_KERNEL); } @@ -1573,11 +1499,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET; cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len, GFP_KERNEL); - if (ifmgd->flags & IEEE80211_STA_EXT_SME) { - /* Wait for SME to decide what to do next */ - ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_recalc_idle(local); - } + /* Wait for SME to decide what to do next */ + ifmgd->state = IEEE80211_STA_MLME_DISABLED; + ieee80211_recalc_idle(local); return; } @@ -1683,8 +1607,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, else sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; - /* If TKIP/WEP is used, no need to parse AP's HT capabilities */ - if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED)) + if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) ieee80211_ht_cap_ie_to_sta_ht_cap(sband, elems.ht_cap_elem, &sta->sta.ht_cap); @@ -1718,7 +1641,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, if (elems.ht_info_elem && elems.wmm_param && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && - !(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED)) + !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, ap_ht_cap_flags); @@ -1931,7 +1854,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param && - !(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED)) { + !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) { struct sta_info *sta; struct ieee80211_supported_band *sband; u16 ap_ht_cap_flags; @@ -2090,26 +2013,6 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata) u16 capa_val = WLAN_CAPABILITY_ESS; struct ieee80211_channel *chan = local->oper_channel; - if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) && - ifmgd->flags & (IEEE80211_STA_AUTO_SSID_SEL | - IEEE80211_STA_AUTO_BSSID_SEL | - IEEE80211_STA_AUTO_CHANNEL_SEL)) { - capa_mask |= WLAN_CAPABILITY_PRIVACY; - if (sdata->default_key) - capa_val |= WLAN_CAPABILITY_PRIVACY; - } - - if (ifmgd->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) - chan = NULL; - - if (ifmgd->flags & IEEE80211_STA_AUTO_BSSID_SEL) - bssid = NULL; - - if (ifmgd->flags & IEEE80211_STA_AUTO_SSID_SEL) { - ssid = NULL; - ssid_len = 0; - } - bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan, bssid, ssid, ssid_len, capa_mask, capa_val); @@ -2119,10 +2022,6 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata) local->oper_channel_type = NL80211_CHAN_NO_HT; ieee80211_hw_config(local, 0); - if (!(ifmgd->flags & IEEE80211_STA_SSID_SET)) - ieee80211_sta_set_ssid(sdata, bss->ssid, - bss->ssid_len); - ieee80211_sta_set_bssid(sdata, bss->cbss.bssid); ieee80211_sta_def_wmm_params(sdata, bss->supp_rates_len, bss->supp_rates); if (sdata->u.mgd.mfp == IEEE80211_MFP_REQUIRED) @@ -2232,14 +2131,6 @@ static void ieee80211_sta_work(struct work_struct *work) WARN_ON(1); break; } - - if (ieee80211_privacy_mismatch(sdata)) { - printk(KERN_DEBUG "%s: privacy configuration mismatch and " - "mixed-cell disabled - disassociate\n", sdata->dev->name); - - ieee80211_set_disassoc(sdata, false, true, - WLAN_REASON_UNSPECIFIED); - } } static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) @@ -2306,9 +2197,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) skb_queue_head_init(&ifmgd->skb_queue); ifmgd->capab = WLAN_CAPABILITY_ESS; - ifmgd->flags |= IEEE80211_STA_CREATE_IBSS | - IEEE80211_STA_AUTO_BSSID_SEL | - IEEE80211_STA_AUTO_CHANNEL_SEL; + ifmgd->flags = 0; if (sdata->local->hw.queues >= 4) ifmgd->flags |= IEEE80211_STA_WMM_ENABLED; @@ -2324,96 +2213,20 @@ void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata) if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) return; - if ((ifmgd->flags & (IEEE80211_STA_BSSID_SET | - IEEE80211_STA_AUTO_BSSID_SEL)) && - (ifmgd->flags & (IEEE80211_STA_SSID_SET | - IEEE80211_STA_AUTO_SSID_SEL))) { - - if (ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) - ieee80211_set_disassoc(sdata, true, true, - WLAN_REASON_DEAUTH_LEAVING); - - if (ifmgd->ssid_len == 0) { - /* - * Only allow association to be started if a valid SSID - * is configured. - */ - return; - } - - if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) || - ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE) - set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request); - else if (ifmgd->flags & IEEE80211_STA_EXT_SME) - set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); - queue_work(local->hw.workqueue, &ifmgd->work); - } -} - -int ieee80211_sta_commit(struct ieee80211_sub_if_data *sdata) -{ - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - - if (ifmgd->ssid_len) - ifmgd->flags |= IEEE80211_STA_SSID_SET; - else - ifmgd->flags &= ~IEEE80211_STA_SSID_SET; - - return 0; -} - -int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len) -{ - struct ieee80211_if_managed *ifmgd; - - if (len > IEEE80211_MAX_SSID_LEN) - return -EINVAL; - - ifmgd = &sdata->u.mgd; - - if (ifmgd->ssid_len != len || memcmp(ifmgd->ssid, ssid, len) != 0) { - if (ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) - ieee80211_set_disassoc(sdata, true, true, - WLAN_REASON_DEAUTH_LEAVING); - - /* - * Do not use reassociation if SSID is changed (different ESS). - */ - ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET; - memset(ifmgd->ssid, 0, sizeof(ifmgd->ssid)); - memcpy(ifmgd->ssid, ssid, len); - ifmgd->ssid_len = len; - } - - return ieee80211_sta_commit(sdata); -} - -int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len) -{ - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - memcpy(ssid, ifmgd->ssid, ifmgd->ssid_len); - *len = ifmgd->ssid_len; - return 0; -} - -int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) -{ - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - - if (compare_ether_addr(bssid, ifmgd->bssid) != 0 && - ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) + if (WARN_ON(ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED)) ieee80211_set_disassoc(sdata, true, true, WLAN_REASON_DEAUTH_LEAVING); - if (is_valid_ether_addr(bssid)) { - memcpy(ifmgd->bssid, bssid, ETH_ALEN); - ifmgd->flags |= IEEE80211_STA_BSSID_SET; - } else { - memset(ifmgd->bssid, 0, ETH_ALEN); - ifmgd->flags &= ~IEEE80211_STA_BSSID_SET; + if (WARN_ON(ifmgd->ssid_len == 0)) { + /* + * Only allow association to be started if a valid SSID + * is configured. + */ + return; } - return ieee80211_sta_commit(sdata); + set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); + queue_work(local->hw.workqueue, &ifmgd->work); } int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, -- cgit v1.2.3 From 517357c685ccc4b5783cc7dbdae8824ada19a97f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 2 Jul 2009 17:18:40 +0200 Subject: cfg80211: assimilate and export ieee80211_bss_get_ie This function from mac80211 seems generally useful, and I will need it in cfg80211 soon. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2d9b6663253c..5748cda659c2 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -46,26 +46,6 @@ static int ecw2cw(int ecw) return (1 << ecw) - 1; } -static u8 *ieee80211_bss_get_ie(struct ieee80211_bss *bss, u8 ie) -{ - u8 *end, *pos; - - pos = bss->cbss.information_elements; - if (pos == NULL) - return NULL; - end = pos + bss->cbss.len_information_elements; - - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) - break; - if (pos[0] == ie) - return pos; - pos += 2 + pos[1]; - } - - return NULL; -} - static int ieee80211_compatible_rates(struct ieee80211_bss *bss, struct ieee80211_supported_band *sband, u32 *rates) @@ -181,7 +161,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) struct ieee80211_local *local = sdata->local; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; - u8 *pos, *ies, *ht_ie; + u8 *pos; + const u8 *ies, *ht_ie; int i, len, count, rates_len, supp_rates_len; u16 capab; struct ieee80211_bss *bss; @@ -345,7 +326,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) */ if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && sband->ht_cap.ht_supported && - (ht_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_INFORMATION)) && + (ht_ie = ieee80211_bss_get_ie(&bss->cbss, WLAN_EID_HT_INFORMATION)) && ht_ie[1] >= sizeof(struct ieee80211_ht_info) && (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))) { struct ieee80211_ht_info *ht_info = -- cgit v1.2.3 From 19957bb399e2722719c0e20c9ae91cf8b6aaff04 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 2 Jul 2009 17:20:43 +0200 Subject: cfg80211: keep track of BSSes In order to avoid problems with BSS structs going away while they're in use, I've long wanted to make cfg80211 keep track of them. Without the SME, that wasn't doable but now that we have the SME we can do this too. It can keep track of up to four separate authentications and one association, regardless of whether it's controlled by the cfg80211 SME or the userspace SME. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 22 +++++++++------------- net/mac80211/mlme.c | 6 +----- 2 files changed, 10 insertions(+), 18 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 7606571d4581..0f29cd0580c9 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1173,6 +1173,7 @@ static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_auth_request *req) { struct ieee80211_sub_if_data *sdata; + const u8 *ssid; sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -1193,15 +1194,16 @@ static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, return -EOPNOTSUPP; } - memcpy(sdata->u.mgd.bssid, req->peer_addr, ETH_ALEN); + memcpy(sdata->u.mgd.bssid, req->bss->bssid, ETH_ALEN); - sdata->local->oper_channel = req->chan; + sdata->local->oper_channel = req->bss->channel; ieee80211_hw_config(sdata->local, 0); - if (!req->ssid) + ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); + if (!ssid) return -EINVAL; - memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len); - sdata->u.mgd.ssid_len = req->ssid_len; + sdata->u.mgd.ssid_len = *(ssid + 1); + memcpy(sdata->u.mgd.ssid, ssid + 2, sdata->u.mgd.ssid_len); kfree(sdata->u.mgd.sme_auth_ie); sdata->u.mgd.sme_auth_ie = NULL; @@ -1227,7 +1229,7 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (memcmp(sdata->u.mgd.bssid, req->peer_addr, ETH_ALEN) != 0 || + if (memcmp(sdata->u.mgd.bssid, req->bss->bssid, ETH_ALEN) != 0 || !(sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED)) return -ENOLINK; /* not authenticated */ @@ -1239,15 +1241,9 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) sdata->u.mgd.flags |= IEEE80211_STA_DISABLE_11N; - sdata->local->oper_channel = req->chan; + sdata->local->oper_channel = req->bss->channel; ieee80211_hw_config(sdata->local, 0); - if (!req->ssid) - return -EINVAL; - - memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len); - sdata->u.mgd.ssid_len = req->ssid_len; - ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len); if (ret && ret != -EALREADY) return ret; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 5748cda659c2..aa1829ae431d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -876,8 +876,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, bss_info_changed |= ieee80211_handle_bss_capability(sdata, bss->cbss.capability, bss->has_erp_value, bss->erp_value); - cfg80211_hold_bss(&bss->cbss); - ieee80211_rx_bss_put(local, bss); } @@ -1031,10 +1029,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, conf->channel->center_freq, ifmgd->ssid, ifmgd->ssid_len); - if (bss) { - cfg80211_unhold_bss(&bss->cbss); + if (bss) ieee80211_rx_bss_put(local, bss); - } if (self_disconnected) { if (deauth) -- cgit v1.2.3 From 96f7e73938da744e718ce4817dd3e7e424624654 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Tue, 30 Jun 2009 14:49:18 +0200 Subject: mac80211: shorten the passive dwell time for sw scans mac80211's software scan implementation uses a passive dwell time of (HZ / 5) which means we stay 200ms on each passive channel. Compared to iwlwifi's hw scan and the old ipw* drivers which use values around 120ms this is quite long. Reducing the passive dwell time from 200ms to 125ms should save us something around a second on cards capable of 11a and we should still be able to catch beacons from most access points (assuming a ~100ms beacon interval). Signed-off-by: Helmut Schaa Signed-off-by: John W. Linville --- net/mac80211/scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 8b2416c77a6e..569a464f60d8 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -26,7 +26,7 @@ #define IEEE80211_PROBE_DELAY (HZ / 33) #define IEEE80211_CHANNEL_TIME (HZ / 33) -#define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 5) +#define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 8) struct ieee80211_bss * ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, -- cgit v1.2.3 From 3e5d7649a64e558e4146ddfad4dfcf13fc65dd47 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jul 2009 14:37:26 +0200 Subject: cfg80211: let SME control reassociation vs. association Since we don't really know that well in the kernel, let's let the SME control whether it wants to use reassociation or not, by allowing it to give the previous BSSID in the associate() parameters. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 6 ++++++ net/mac80211/mlme.c | 7 ------- 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 0f29cd0580c9..e6d8860f26f2 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1256,6 +1256,12 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED; } + if (req->prev_bssid) { + sdata->u.mgd.flags |= IEEE80211_STA_PREV_BSSID_SET; + memcpy(sdata->u.mgd.prev_bssid, req->prev_bssid, ETH_ALEN); + } else + sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET; + if (req->crypto.control_port) sdata->u.mgd.flags |= IEEE80211_STA_CONTROL_PORT; else diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index aa1829ae431d..24486455e505 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -879,9 +879,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, ieee80211_rx_bss_put(local, bss); } - ifmgd->flags |= IEEE80211_STA_PREV_BSSID_SET; - memcpy(ifmgd->prev_bssid, sdata->u.mgd.bssid, ETH_ALEN); - ifmgd->last_probe = jiffies; ieee80211_led_assoc(local, 1); @@ -1470,10 +1467,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, if (status_code != WLAN_STATUS_SUCCESS) { printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", sdata->dev->name, status_code); - /* if this was a reassociation, ensure we try a "full" - * association next time. This works around some broken APs - * which do not correctly reject reassociation requests. */ - ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET; cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len, GFP_KERNEL); /* Wait for SME to decide what to do next */ -- cgit v1.2.3 From a7c1cfc9616ee76213a6d4fd4c17f13fdc92ddce Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jul 2009 03:45:16 +0200 Subject: mac80211: remove dead code from mlme The ap_capab and last_probe struct members are unused. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/debugfs_netdev.c | 3 --- net/mac80211/ieee80211_i.h | 4 +--- net/mac80211/mlme.c | 2 -- 3 files changed, 1 insertion(+), 8 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index ffe9add3ef42..4c541f0f325f 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -100,7 +100,6 @@ IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); IEEE80211_IF_FILE(prev_bssid, u.mgd.prev_bssid, MAC); IEEE80211_IF_FILE(ssid_len, u.mgd.ssid_len, SIZE); IEEE80211_IF_FILE(aid, u.mgd.aid, DEC); -IEEE80211_IF_FILE(ap_capab, u.mgd.ap_capab, HEX); IEEE80211_IF_FILE(capab, u.mgd.capab, HEX); IEEE80211_IF_FILE(extra_ie_len, u.mgd.extra_ie_len, SIZE); IEEE80211_IF_FILE(auth_tries, u.mgd.auth_tries, DEC); @@ -186,7 +185,6 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_ADD(prev_bssid, sta); DEBUGFS_ADD(ssid_len, sta); DEBUGFS_ADD(aid, sta); - DEBUGFS_ADD(ap_capab, sta); DEBUGFS_ADD(capab, sta); DEBUGFS_ADD(extra_ie_len, sta); DEBUGFS_ADD(auth_tries, sta); @@ -318,7 +316,6 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_DEL(prev_bssid, sta); DEBUGFS_DEL(ssid_len, sta); DEBUGFS_DEL(aid, sta); - DEBUGFS_DEL(ap_capab, sta); DEBUGFS_DEL(capab, sta); DEBUGFS_DEL(extra_ie_len, sta); DEBUGFS_DEL(auth_tries, sta); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a550aeb85053..d0354b16d24f 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -268,7 +268,7 @@ struct ieee80211_if_managed { } state; u16 aid; - u16 ap_capab, capab; + u16 capab; u8 *extra_ie; /* to be added to the end of AssocReq */ size_t extra_ie_len; @@ -288,7 +288,6 @@ struct ieee80211_if_managed { unsigned long request; - unsigned long last_probe; unsigned long last_beacon; unsigned int flags; @@ -472,7 +471,6 @@ struct ieee80211_sub_if_data { struct dentry *prev_bssid; struct dentry *ssid_len; struct dentry *aid; - struct dentry *ap_capab; struct dentry *capab; struct dentry *extra_ie_len; struct dentry *auth_tries; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 24486455e505..29575eea3ed1 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -879,7 +879,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, ieee80211_rx_bss_put(local, bss); } - ifmgd->last_probe = jiffies; ieee80211_led_assoc(local, 1); sdata->vif.bss_conf.assoc = 1; @@ -1488,7 +1487,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: associated\n", sdata->dev->name); ifmgd->aid = aid; - ifmgd->ap_capab = capab_info; kfree(ifmgd->assocresp_ies); ifmgd->assocresp_ies_len = len - (pos - (u8 *) mgmt); -- cgit v1.2.3 From 77fdaa12cea26c204cc12c312fe40bc0f3dcdfd8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jul 2009 03:45:17 +0200 Subject: mac80211: rework MLME for multiple authentications Sit tight. This shakes up the world as you know it. Let go of your spaghetti tongs, they will no longer be required, the horrible statemachine in net/mac80211/mlme.c is no more... With the cfg80211 SME mac80211 now has much less to keep track of, but, on the other hand, for FT it needs to be able to keep track of at least one authentication being in progress while associated. So convert from a single state machine to having small ones for all the different things we need to do. For real FT it will still need work wrt. PS, but this should be a good step. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 105 +--- net/mac80211/debugfs_netdev.c | 38 -- net/mac80211/ieee80211_i.h | 86 ++- net/mac80211/iface.c | 28 +- net/mac80211/mlme.c | 1332 ++++++++++++++++++++++------------------- net/mac80211/rx.c | 29 +- net/mac80211/scan.c | 23 +- 7 files changed, 750 insertions(+), 891 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index e6d8860f26f2..7cfc14e4ca07 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1172,122 +1172,25 @@ static int ieee80211_scan(struct wiphy *wiphy, static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_auth_request *req) { - struct ieee80211_sub_if_data *sdata; - const u8 *ssid; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - switch (req->auth_type) { - case NL80211_AUTHTYPE_OPEN_SYSTEM: - sdata->u.mgd.auth_alg = WLAN_AUTH_OPEN; - break; - case NL80211_AUTHTYPE_SHARED_KEY: - sdata->u.mgd.auth_alg = WLAN_AUTH_SHARED_KEY; - break; - case NL80211_AUTHTYPE_FT: - sdata->u.mgd.auth_alg = WLAN_AUTH_FT; - break; - case NL80211_AUTHTYPE_NETWORK_EAP: - sdata->u.mgd.auth_alg = WLAN_AUTH_LEAP; - break; - default: - return -EOPNOTSUPP; - } - - memcpy(sdata->u.mgd.bssid, req->bss->bssid, ETH_ALEN); - - sdata->local->oper_channel = req->bss->channel; - ieee80211_hw_config(sdata->local, 0); - - ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); - if (!ssid) - return -EINVAL; - sdata->u.mgd.ssid_len = *(ssid + 1); - memcpy(sdata->u.mgd.ssid, ssid + 2, sdata->u.mgd.ssid_len); - - kfree(sdata->u.mgd.sme_auth_ie); - sdata->u.mgd.sme_auth_ie = NULL; - sdata->u.mgd.sme_auth_ie_len = 0; - if (req->ie) { - sdata->u.mgd.sme_auth_ie = kmalloc(req->ie_len, GFP_KERNEL); - if (sdata->u.mgd.sme_auth_ie == NULL) - return -ENOMEM; - memcpy(sdata->u.mgd.sme_auth_ie, req->ie, req->ie_len); - sdata->u.mgd.sme_auth_ie_len = req->ie_len; - } - - sdata->u.mgd.state = IEEE80211_STA_MLME_DIRECT_PROBE; - ieee80211_sta_req_auth(sdata); - return 0; + return ieee80211_mgd_auth(IEEE80211_DEV_TO_SUB_IF(dev), req); } static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_assoc_request *req) { - struct ieee80211_sub_if_data *sdata; - int ret, i; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (memcmp(sdata->u.mgd.bssid, req->bss->bssid, ETH_ALEN) != 0 || - !(sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED)) - return -ENOLINK; /* not authenticated */ - - sdata->u.mgd.flags &= ~IEEE80211_STA_DISABLE_11N; - - for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) - if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || - req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || - req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) - sdata->u.mgd.flags |= IEEE80211_STA_DISABLE_11N; - - sdata->local->oper_channel = req->bss->channel; - ieee80211_hw_config(sdata->local, 0); - - ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len); - if (ret && ret != -EALREADY) - return ret; - - if (req->use_mfp) { - sdata->u.mgd.mfp = IEEE80211_MFP_REQUIRED; - sdata->u.mgd.flags |= IEEE80211_STA_MFP_ENABLED; - } else { - sdata->u.mgd.mfp = IEEE80211_MFP_DISABLED; - sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED; - } - - if (req->prev_bssid) { - sdata->u.mgd.flags |= IEEE80211_STA_PREV_BSSID_SET; - memcpy(sdata->u.mgd.prev_bssid, req->prev_bssid, ETH_ALEN); - } else - sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET; - - if (req->crypto.control_port) - sdata->u.mgd.flags |= IEEE80211_STA_CONTROL_PORT; - else - sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; - - sdata->u.mgd.state = IEEE80211_STA_MLME_ASSOCIATE; - ieee80211_sta_req_auth(sdata); - return 0; + return ieee80211_mgd_assoc(IEEE80211_DEV_TO_SUB_IF(dev), req); } static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_deauth_request *req) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - /* TODO: req->ie, req->peer_addr */ - return ieee80211_sta_deauthenticate(sdata, req->reason_code); + return ieee80211_mgd_deauth(IEEE80211_DEV_TO_SUB_IF(dev), req); } static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_disassoc_request *req) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - /* TODO: req->ie, req->peer_addr */ - return ieee80211_sta_disassociate(sdata, req->reason_code); + return ieee80211_mgd_disassoc(IEEE80211_DEV_TO_SUB_IF(dev), req); } static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 4c541f0f325f..e9ec6cae2d39 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -95,29 +95,9 @@ IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC); IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC); /* STA attributes */ -IEEE80211_IF_FILE(state, u.mgd.state, DEC); IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); -IEEE80211_IF_FILE(prev_bssid, u.mgd.prev_bssid, MAC); -IEEE80211_IF_FILE(ssid_len, u.mgd.ssid_len, SIZE); IEEE80211_IF_FILE(aid, u.mgd.aid, DEC); IEEE80211_IF_FILE(capab, u.mgd.capab, HEX); -IEEE80211_IF_FILE(extra_ie_len, u.mgd.extra_ie_len, SIZE); -IEEE80211_IF_FILE(auth_tries, u.mgd.auth_tries, DEC); -IEEE80211_IF_FILE(assoc_tries, u.mgd.assoc_tries, DEC); -IEEE80211_IF_FILE(auth_alg, u.mgd.auth_alg, DEC); -IEEE80211_IF_FILE(auth_transaction, u.mgd.auth_transaction, DEC); - -static ssize_t ieee80211_if_fmt_flags( - const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) -{ - return scnprintf(buf, buflen, "%s%s%s%s%s\n", - sdata->u.mgd.flags & IEEE80211_STA_PREV_BSSID_SET ? "prev BSSID\n" : "", - sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "", - sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "", - sdata->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "", - sdata->vif.bss_conf.use_cts_prot ? "CTS prot\n" : ""); -} -__IEEE80211_IF_FILE(flags); /* AP attributes */ IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); @@ -180,18 +160,9 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_ADD(force_unicast_rateidx, sta); DEBUGFS_ADD(max_ratectrl_rateidx, sta); - DEBUGFS_ADD(state, sta); DEBUGFS_ADD(bssid, sta); - DEBUGFS_ADD(prev_bssid, sta); - DEBUGFS_ADD(ssid_len, sta); DEBUGFS_ADD(aid, sta); DEBUGFS_ADD(capab, sta); - DEBUGFS_ADD(extra_ie_len, sta); - DEBUGFS_ADD(auth_tries, sta); - DEBUGFS_ADD(assoc_tries, sta); - DEBUGFS_ADD(auth_alg, sta); - DEBUGFS_ADD(auth_transaction, sta); - DEBUGFS_ADD(flags, sta); } static void add_ap_files(struct ieee80211_sub_if_data *sdata) @@ -311,18 +282,9 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_DEL(force_unicast_rateidx, sta); DEBUGFS_DEL(max_ratectrl_rateidx, sta); - DEBUGFS_DEL(state, sta); DEBUGFS_DEL(bssid, sta); - DEBUGFS_DEL(prev_bssid, sta); - DEBUGFS_DEL(ssid_len, sta); DEBUGFS_DEL(aid, sta); DEBUGFS_DEL(capab, sta); - DEBUGFS_DEL(extra_ie_len, sta); - DEBUGFS_DEL(auth_tries, sta); - DEBUGFS_DEL(assoc_tries, sta); - DEBUGFS_DEL(auth_alg, sta); - DEBUGFS_DEL(auth_transaction, sta); - DEBUGFS_DEL(flags, sta); } static void del_ap_files(struct ieee80211_sub_if_data *sdata) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index d0354b16d24f..2e92bbd9b2d0 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -227,11 +227,32 @@ struct mesh_preq_queue { u8 flags; }; +enum ieee80211_mgd_state { + IEEE80211_MGD_STATE_IDLE, + IEEE80211_MGD_STATE_PROBE, + IEEE80211_MGD_STATE_AUTH, + IEEE80211_MGD_STATE_ASSOC, +}; + +struct ieee80211_mgd_work { + struct list_head list; + struct ieee80211_bss *bss; + int ie_len; + u8 prev_bssid[ETH_ALEN]; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 ssid_len; + unsigned long timeout; + enum ieee80211_mgd_state state; + u16 auth_alg, auth_transaction; + + int tries; + + /* must be last */ + u8 ie[0]; /* for auth or assoc frame, not probe */ +}; + /* flags used in struct ieee80211_if_managed.flags */ enum ieee80211_sta_flags { - IEEE80211_STA_PREV_BSSID_SET = BIT(0), - IEEE80211_STA_AUTHENTICATED = BIT(1), - IEEE80211_STA_ASSOCIATED = BIT(2), IEEE80211_STA_PROBEREQ_POLL = BIT(3), IEEE80211_STA_CONTROL_PORT = BIT(4), IEEE80211_STA_WMM_ENABLED = BIT(5), @@ -243,8 +264,6 @@ enum ieee80211_sta_flags { /* flags for MLME request */ enum ieee80211_sta_request { IEEE80211_STA_REQ_SCAN, - IEEE80211_STA_REQ_AUTH, - IEEE80211_STA_REQ_RUN, }; struct ieee80211_if_managed { @@ -254,35 +273,17 @@ struct ieee80211_if_managed { struct work_struct chswitch_work; struct work_struct beacon_loss_work; - u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; + struct mutex mtx; + struct ieee80211_bss *associated; + struct list_head work_list; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - size_t ssid_len; - - enum { - IEEE80211_STA_MLME_DISABLED, - IEEE80211_STA_MLME_DIRECT_PROBE, - IEEE80211_STA_MLME_AUTHENTICATE, - IEEE80211_STA_MLME_ASSOCIATE, - IEEE80211_STA_MLME_ASSOCIATED, - } state; + u8 bssid[ETH_ALEN]; u16 aid; u16 capab; - u8 *extra_ie; /* to be added to the end of AssocReq */ - size_t extra_ie_len; - - /* The last AssocReq/Resp IEs */ - u8 *assocreq_ies, *assocresp_ies; - size_t assocreq_ies_len, assocresp_ies_len; struct sk_buff_head skb_queue; - int assoc_scan_tries; /* number of scans done pre-association */ - int direct_probe_tries; /* retries for direct probes */ - int auth_tries; /* retries for auth req */ - int assoc_tries; /* retries for assoc req */ - unsigned long timers_running; /* used for quiesce/restart */ bool powersave; /* powersave requested for this iface */ @@ -292,9 +293,6 @@ struct ieee80211_if_managed { unsigned int flags; - int auth_alg; /* currently used IEEE 802.11 authentication algorithm */ - int auth_transaction; - u32 beacon_crc; enum { @@ -304,10 +302,6 @@ struct ieee80211_if_managed { } mfp; /* management frame protection */ int wmm_last_param_set; - - /* Extra IE data for management frames */ - u8 *sme_auth_ie; - size_t sme_auth_ie_len; }; enum ieee80211_ibss_request { @@ -466,18 +460,9 @@ struct ieee80211_sub_if_data { union { struct { struct dentry *drop_unencrypted; - struct dentry *state; struct dentry *bssid; - struct dentry *prev_bssid; - struct dentry *ssid_len; struct dentry *aid; struct dentry *capab; - struct dentry *extra_ie_len; - struct dentry *auth_tries; - struct dentry *assoc_tries; - struct dentry *auth_alg; - struct dentry *auth_transaction; - struct dentry *flags; struct dentry *force_unicast_rateidx; struct dentry *max_ratectrl_rateidx; } sta; @@ -928,11 +913,16 @@ extern const struct iw_handler_def ieee80211_iw_handler_def; /* STA code */ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata); +int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, + struct cfg80211_auth_request *req); +int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, + struct cfg80211_assoc_request *req); +int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, + struct cfg80211_deauth_request *req); +int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, + struct cfg80211_disassoc_request *req); ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); -void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata); -int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason); -int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason); void ieee80211_send_pspoll(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata); void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency); @@ -966,8 +956,6 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, void ieee80211_scan_cancel(struct ieee80211_local *local); ieee80211_rx_result ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); -int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, - const char *ie, size_t len); void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); struct ieee80211_bss * @@ -983,8 +971,6 @@ ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, u8 *ssid, u8 ssid_len); void ieee80211_rx_bss_put(struct ieee80211_local *local, struct ieee80211_bss *bss); -void ieee80211_rx_bss_remove(struct ieee80211_sub_if_data *sdata, u8 *bssid, - int freq, u8 *ssid, u8 ssid_len); /* interface handling */ int ieee80211_if_add(struct ieee80211_local *local, const char *name, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index b87bf425f857..4839a2d97a3b 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -233,9 +233,6 @@ static int ieee80211_open(struct net_device *dev) ieee80211_configure_filter(local); netif_addr_unlock_bh(local->mdev); break; - case NL80211_IFTYPE_STATION: - sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET; - /* fall through */ default: conf.vif = &sdata->vif; conf.type = sdata->vif.type; @@ -365,18 +362,6 @@ static int ieee80211_stop(struct net_device *dev) rcu_read_unlock(); - /* - * Announce that we are leaving the network, in case we are a - * station interface type. This must be done before removing - * all stations associated with sta_info_flush, otherwise STA - * information will be gone and no announce being done. - */ - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - if (sdata->u.mgd.state != IEEE80211_STA_MLME_DISABLED) - ieee80211_sta_deauthenticate(sdata, - WLAN_REASON_DEAUTH_LEAVING); - } - /* * Remove all stations associated with this interface. * @@ -462,7 +447,6 @@ static int ieee80211_stop(struct net_device *dev) netif_addr_unlock_bh(local->mdev); break; case NL80211_IFTYPE_STATION: - memset(sdata->u.mgd.bssid, 0, ETH_ALEN); del_timer_sync(&sdata->u.mgd.chswitch_timer); del_timer_sync(&sdata->u.mgd.timer); /* @@ -485,10 +469,6 @@ static int ieee80211_stop(struct net_device *dev) */ synchronize_rcu(); skb_queue_purge(&sdata->u.mgd.skb_queue); - - kfree(sdata->u.mgd.extra_ie); - sdata->u.mgd.extra_ie = NULL; - sdata->u.mgd.extra_ie_len = 0; /* fall through */ case NL80211_IFTYPE_ADHOC: if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { @@ -650,11 +630,6 @@ static void ieee80211_teardown_sdata(struct net_device *dev) kfree_skb(sdata->u.ibss.presp); break; case NL80211_IFTYPE_STATION: - kfree(sdata->u.mgd.extra_ie); - kfree(sdata->u.mgd.assocreq_ies); - kfree(sdata->u.mgd.assocresp_ies); - kfree(sdata->u.mgd.sme_auth_ie); - break; case NL80211_IFTYPE_WDS: case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_MONITOR: @@ -937,7 +912,8 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) continue; /* do not count disabled managed interfaces */ if (sdata->vif.type == NL80211_IFTYPE_STATION && - sdata->u.mgd.state == IEEE80211_STA_MLME_DISABLED) + !sdata->u.mgd.associated && + list_empty(&sdata->u.mgd.work_list)) continue; /* do not count unused IBSS interfaces */ if (sdata->vif.type == NL80211_IFTYPE_ADHOC && diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 29575eea3ed1..108e8c9c60fd 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -27,20 +27,51 @@ #include "rate.h" #include "led.h" -#define IEEE80211_ASSOC_SCANS_MAX_TRIES 2 #define IEEE80211_AUTH_TIMEOUT (HZ / 5) #define IEEE80211_AUTH_MAX_TRIES 3 #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) #define IEEE80211_ASSOC_MAX_TRIES 3 #define IEEE80211_MONITORING_INTERVAL (2 * HZ) #define IEEE80211_PROBE_WAIT (HZ / 5) -#define IEEE80211_PROBE_IDLE_TIME (60 * HZ) -#define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) #define TMR_RUNNING_TIMER 0 #define TMR_RUNNING_CHANSW 1 +/* + * All cfg80211 functions have to be called outside a locked + * section so that they can acquire a lock themselves... This + * is much simpler than queuing up things in cfg80211, but we + * do need some indirection for that here. + */ +enum rx_mgmt_action { + /* no action required */ + RX_MGMT_NONE, + + /* caller must call cfg80211_send_rx_auth() */ + RX_MGMT_CFG80211_AUTH, + + /* caller must call cfg80211_send_rx_assoc() */ + RX_MGMT_CFG80211_ASSOC, + + /* caller must call cfg80211_send_deauth() */ + RX_MGMT_CFG80211_DEAUTH, + + /* caller must call cfg80211_send_disassoc() */ + RX_MGMT_CFG80211_DISASSOC, + + /* caller must call cfg80211_auth_timeout() & free work */ + RX_MGMT_CFG80211_AUTH_TO, + + /* caller must call cfg80211_assoc_timeout() & free work */ + RX_MGMT_CFG80211_ASSOC_TO, +}; + /* utils */ +static inline void ASSERT_MGD_MTX(struct ieee80211_if_managed *ifmgd) +{ + WARN_ON(!mutex_is_locked(&ifmgd->mtx)); +} + static int ecw2cw(int ecw) { return (1 << ecw) - 1; @@ -74,11 +105,10 @@ static int ieee80211_compatible_rates(struct ieee80211_bss *bss, */ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, struct ieee80211_ht_info *hti, - u16 ap_ht_cap_flags) + const u8 *bssid, u16 ap_ht_cap_flags) { struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct sta_info *sta; u32 changed = 0; u16 ht_opmode; @@ -127,12 +157,10 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, ieee80211_hw_config(local, 0); rcu_read_lock(); - - sta = sta_info_get(local, ifmgd->bssid); + sta = sta_info_get(local, bssid); if (sta) rate_control_rate_update(local, sband, sta, IEEE80211_RC_HT_CHANGED); - rcu_read_unlock(); } @@ -155,7 +183,8 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, /* frame sending functions */ -static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) +static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; @@ -165,14 +194,13 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) const u8 *ies, *ht_ie; int i, len, count, rates_len, supp_rates_len; u16 capab; - struct ieee80211_bss *bss; int wmm = 0; struct ieee80211_supported_band *sband; u32 rates = 0; skb = dev_alloc_skb(local->hw.extra_tx_headroom + - sizeof(*mgmt) + 200 + ifmgd->extra_ie_len + - ifmgd->ssid_len); + sizeof(*mgmt) + 200 + wk->ie_len + + wk->ssid_len); if (!skb) { printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " "frame\n", sdata->dev->name); @@ -191,45 +219,35 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; } - bss = ieee80211_rx_bss_get(local, ifmgd->bssid, - local->hw.conf.channel->center_freq, - ifmgd->ssid, ifmgd->ssid_len); - if (bss) { - if (bss->cbss.capability & WLAN_CAPABILITY_PRIVACY) - capab |= WLAN_CAPABILITY_PRIVACY; - if (bss->wmm_used) - wmm = 1; + if (wk->bss->cbss.capability & WLAN_CAPABILITY_PRIVACY) + capab |= WLAN_CAPABILITY_PRIVACY; + if (wk->bss->wmm_used) + wmm = 1; - /* get all rates supported by the device and the AP as - * some APs don't like getting a superset of their rates - * in the association request (e.g. D-Link DAP 1353 in - * b-only mode) */ - rates_len = ieee80211_compatible_rates(bss, sband, &rates); + /* get all rates supported by the device and the AP as + * some APs don't like getting a superset of their rates + * in the association request (e.g. D-Link DAP 1353 in + * b-only mode) */ + rates_len = ieee80211_compatible_rates(wk->bss, sband, &rates); - if ((bss->cbss.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && - (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) - capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; - - ieee80211_rx_bss_put(local, bss); - } else { - rates = ~0; - rates_len = sband->n_bitrates; - } + if ((wk->bss->cbss.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && + (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) + capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); memset(mgmt, 0, 24); - memcpy(mgmt->da, ifmgd->bssid, ETH_ALEN); + memcpy(mgmt->da, wk->bss->cbss.bssid, ETH_ALEN); memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); - memcpy(mgmt->bssid, ifmgd->bssid, ETH_ALEN); + memcpy(mgmt->bssid, wk->bss->cbss.bssid, ETH_ALEN); - if (ifmgd->flags & IEEE80211_STA_PREV_BSSID_SET) { + if (!is_zero_ether_addr(wk->prev_bssid)) { skb_put(skb, 10); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_REASSOC_REQ); mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); mgmt->u.reassoc_req.listen_interval = cpu_to_le16(local->hw.conf.listen_interval); - memcpy(mgmt->u.reassoc_req.current_ap, ifmgd->prev_bssid, + memcpy(mgmt->u.reassoc_req.current_ap, wk->prev_bssid, ETH_ALEN); } else { skb_put(skb, 4); @@ -241,10 +259,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) } /* SSID */ - ies = pos = skb_put(skb, 2 + ifmgd->ssid_len); + ies = pos = skb_put(skb, 2 + wk->ssid_len); *pos++ = WLAN_EID_SSID; - *pos++ = ifmgd->ssid_len; - memcpy(pos, ifmgd->ssid, ifmgd->ssid_len); + *pos++ = wk->ssid_len; + memcpy(pos, wk->ssid, wk->ssid_len); /* add all rates which were marked to be used above */ supp_rates_len = rates_len; @@ -299,9 +317,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) } } - if (ifmgd->extra_ie) { - pos = skb_put(skb, ifmgd->extra_ie_len); - memcpy(pos, ifmgd->extra_ie, ifmgd->extra_ie_len); + if (wk->ie_len && wk->ie) { + pos = skb_put(skb, wk->ie_len); + memcpy(pos, wk->ie, wk->ie_len); } if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) { @@ -326,7 +344,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) */ if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && sband->ht_cap.ht_supported && - (ht_ie = ieee80211_bss_get_ie(&bss->cbss, WLAN_EID_HT_INFORMATION)) && + (ht_ie = ieee80211_bss_get_ie(&wk->bss->cbss, WLAN_EID_HT_INFORMATION)) && ht_ie[1] >= sizeof(struct ieee80211_ht_info) && (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))) { struct ieee80211_ht_info *ht_info = @@ -363,18 +381,12 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); } - kfree(ifmgd->assocreq_ies); - ifmgd->assocreq_ies_len = (skb->data + skb->len) - ies; - ifmgd->assocreq_ies = kmalloc(ifmgd->assocreq_ies_len, GFP_KERNEL); - if (ifmgd->assocreq_ies) - memcpy(ifmgd->assocreq_ies, ies, ifmgd->assocreq_ies_len); - ieee80211_tx_skb(sdata, skb, 0); } static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, - u16 stype, u16 reason) + const u8 *bssid, u16 stype, u16 reason) { struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; @@ -391,9 +403,9 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); memset(mgmt, 0, 24); - memcpy(mgmt->da, ifmgd->bssid, ETH_ALEN); + memcpy(mgmt->da, bssid, ETH_ALEN); memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); - memcpy(mgmt->bssid, ifmgd->bssid, ETH_ALEN); + memcpy(mgmt->bssid, bssid, ETH_ALEN); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); skb_put(skb, 2); /* u.deauth.reason_code == u.disassoc.reason_code */ @@ -477,28 +489,26 @@ static void ieee80211_chswitch_work(struct work_struct *work) { struct ieee80211_sub_if_data *sdata = container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); - struct ieee80211_bss *bss; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; if (!netif_running(sdata->dev)) return; - bss = ieee80211_rx_bss_get(sdata->local, ifmgd->bssid, - sdata->local->hw.conf.channel->center_freq, - ifmgd->ssid, ifmgd->ssid_len); - if (!bss) - goto exit; + mutex_lock(&ifmgd->mtx); + if (!ifmgd->associated) + goto out; sdata->local->oper_channel = sdata->local->csa_channel; + ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL); + /* XXX: shouldn't really modify cfg80211-owned data! */ - if (!ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL)) - bss->cbss.channel = sdata->local->oper_channel; + ifmgd->associated->cbss.channel = sdata->local->oper_channel; - ieee80211_rx_bss_put(sdata->local, bss); -exit: - ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; ieee80211_wake_queues_by_reason(&sdata->local->hw, IEEE80211_QUEUE_STOP_REASON_CSA); + out: + ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; + mutex_unlock(&ifmgd->mtx); } static void ieee80211_chswitch_timer(unsigned long data) @@ -523,7 +533,9 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num); - if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATED) + ASSERT_MGD_MTX(ifmgd); + + if (!ifmgd->associated) return; if (sdata->local->sw_scanning || sdata->local->hw_scanning) @@ -634,7 +646,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) } if (count == 1 && found->u.mgd.powersave && - (found->u.mgd.flags & IEEE80211_STA_ASSOCIATED) && + found->u.mgd.associated && list_empty(&found->u.mgd.work_list) && !(found->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL)) { s32 beaconint_us; @@ -789,9 +801,6 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, u16 capab, bool erp_valid, u8 erp) { struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; -#endif u32 changed = 0; bool use_protection; bool use_short_preamble; @@ -808,42 +817,16 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME); if (use_protection != bss_conf->use_cts_prot) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: CTS protection %s (BSSID=%pM)\n", - sdata->dev->name, - use_protection ? "enabled" : "disabled", - ifmgd->bssid); - } -#endif bss_conf->use_cts_prot = use_protection; changed |= BSS_CHANGED_ERP_CTS_PROT; } if (use_short_preamble != bss_conf->use_short_preamble) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: switched to %s barker preamble" - " (BSSID=%pM)\n", - sdata->dev->name, - use_short_preamble ? "short" : "long", - ifmgd->bssid); - } -#endif bss_conf->use_short_preamble = use_short_preamble; changed |= BSS_CHANGED_ERP_PREAMBLE; } if (use_short_slot != bss_conf->use_short_slot) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: switched to %s slot time" - " (BSSID=%pM)\n", - sdata->dev->name, - use_short_slot ? "short" : "long", - ifmgd->bssid); - } -#endif bss_conf->use_short_slot = use_short_slot; changed |= BSS_CHANGED_ERP_SLOT; } @@ -852,32 +835,23 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, } static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, + struct ieee80211_bss *bss, u32 bss_info_changed) { - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; - struct ieee80211_conf *conf = &local_to_hw(local)->conf; - - struct ieee80211_bss *bss; bss_info_changed |= BSS_CHANGED_ASSOC; - ifmgd->flags |= IEEE80211_STA_ASSOCIATED; + /* set timing information */ + sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval; + sdata->vif.bss_conf.timestamp = bss->cbss.tsf; + sdata->vif.bss_conf.dtim_period = bss->dtim_period; - bss = ieee80211_rx_bss_get(local, ifmgd->bssid, - conf->channel->center_freq, - ifmgd->ssid, ifmgd->ssid_len); - if (bss) { - /* set timing information */ - sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval; - sdata->vif.bss_conf.timestamp = bss->cbss.tsf; - sdata->vif.bss_conf.dtim_period = bss->dtim_period; + bss_info_changed |= BSS_CHANGED_BEACON_INT; + bss_info_changed |= ieee80211_handle_bss_capability(sdata, + bss->cbss.capability, bss->has_erp_value, bss->erp_value); - bss_info_changed |= BSS_CHANGED_BEACON_INT; - bss_info_changed |= ieee80211_handle_bss_capability(sdata, - bss->cbss.capability, bss->has_erp_value, bss->erp_value); - - ieee80211_rx_bss_put(local, bss); - } + sdata->u.mgd.associated = bss; + memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN); ieee80211_led_assoc(local, 1); @@ -905,152 +879,133 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, netif_carrier_on(sdata->dev); } -static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata) +static enum rx_mgmt_action __must_check +ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; - ifmgd->direct_probe_tries++; - if (ifmgd->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) { + wk->tries++; + if (wk->tries > IEEE80211_AUTH_MAX_TRIES) { printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", - sdata->dev->name, ifmgd->bssid); - ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_recalc_idle(local); - cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid, - GFP_KERNEL); + sdata->dev->name, wk->bss->cbss.bssid); /* * Most likely AP is not in the range so remove the - * bss information associated to the AP + * bss struct for that AP. */ - ieee80211_rx_bss_remove(sdata, ifmgd->bssid, - sdata->local->hw.conf.channel->center_freq, - ifmgd->ssid, ifmgd->ssid_len); + cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss); /* * We might have a pending scan which had no chance to run yet - * due to state == IEEE80211_STA_MLME_DIRECT_PROBE. - * Hence, queue the STAs work again + * due to work needing to be done. Hence, queue the STAs work + * again for that. */ queue_work(local->hw.workqueue, &ifmgd->work); - return; + return RX_MGMT_CFG80211_AUTH_TO; } - printk(KERN_DEBUG "%s: direct probe to AP %pM try %d\n", - sdata->dev->name, ifmgd->bssid, - ifmgd->direct_probe_tries); + printk(KERN_DEBUG "%s: direct probe to AP %pM (try %d)\n", + sdata->dev->name, wk->bss->cbss.bssid, + wk->tries); - ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE; - - /* Direct probe is sent to broadcast address as some APs + /* + * Direct probe is sent to broadcast address as some APs * will not answer to direct packet in unassociated state. */ - ieee80211_send_probe_req(sdata, NULL, - ifmgd->ssid, ifmgd->ssid_len, NULL, 0); + ieee80211_send_probe_req(sdata, NULL, wk->ssid, wk->ssid_len, NULL, 0); + + wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; + mod_timer(&ifmgd->timer, wk->timeout); - mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT); + return RX_MGMT_NONE; } -static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata) +static enum rx_mgmt_action __must_check +ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; - ifmgd->auth_tries++; - if (ifmgd->auth_tries > IEEE80211_AUTH_MAX_TRIES) { + wk->tries++; + if (wk->tries > IEEE80211_AUTH_MAX_TRIES) { printk(KERN_DEBUG "%s: authentication with AP %pM" " timed out\n", - sdata->dev->name, ifmgd->bssid); - ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_recalc_idle(local); - cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid, - GFP_KERNEL); - ieee80211_rx_bss_remove(sdata, ifmgd->bssid, - sdata->local->hw.conf.channel->center_freq, - ifmgd->ssid, ifmgd->ssid_len); + sdata->dev->name, wk->bss->cbss.bssid); + + /* + * Most likely AP is not in the range so remove the + * bss struct for that AP. + */ + cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss); /* * We might have a pending scan which had no chance to run yet - * due to state == IEEE80211_STA_MLME_AUTHENTICATE. - * Hence, queue the STAs work again + * due to work needing to be done. Hence, queue the STAs work + * again for that. */ queue_work(local->hw.workqueue, &ifmgd->work); - return; + return RX_MGMT_CFG80211_AUTH_TO; } - ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE; - printk(KERN_DEBUG "%s: authenticate with AP %pM\n", - sdata->dev->name, ifmgd->bssid); + printk(KERN_DEBUG "%s: authenticate with AP %pM (try %d)\n", + sdata->dev->name, wk->bss->cbss.bssid, wk->tries); + + ieee80211_send_auth(sdata, 1, wk->auth_alg, wk->ie, wk->ie_len, + wk->bss->cbss.bssid, 0); + wk->auth_transaction = 2; - ieee80211_send_auth(sdata, 1, ifmgd->auth_alg, ifmgd->sme_auth_ie, - ifmgd->sme_auth_ie_len, ifmgd->bssid, 0); - ifmgd->auth_transaction = 2; + wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; + mod_timer(&ifmgd->timer, wk->timeout); - mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT); + return RX_MGMT_NONE; } -/* - * The disassoc 'reason' argument can be either our own reason - * if self disconnected or a reason code from the AP. - */ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, - bool deauth, bool self_disconnected, - u16 reason) + const u8 *bssid, bool deauth) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; - struct ieee80211_conf *conf = &local_to_hw(local)->conf; - struct ieee80211_bss *bss; struct sta_info *sta; u32 changed = 0, config_changed = 0; - if (deauth) { - ifmgd->direct_probe_tries = 0; - ifmgd->auth_tries = 0; - } - ifmgd->assoc_scan_tries = 0; - ifmgd->assoc_tries = 0; + ASSERT_MGD_MTX(ifmgd); + + ifmgd->associated = NULL; + memset(ifmgd->bssid, 0, ETH_ALEN); + + /* + * we need to commit the associated = NULL change because the + * scan code uses that to determine whether this iface should + * go to/wake up from powersave or not -- and could otherwise + * wake the queues erroneously. + */ + smp_mb(); + + /* + * Thus, we can only afterwards stop the queues -- to account + * for the case where another CPU is finishing a scan at this + * time -- we don't want the scan code to enable queues. + */ netif_tx_stop_all_queues(sdata->dev); netif_carrier_off(sdata->dev); rcu_read_lock(); - sta = sta_info_get(local, ifmgd->bssid); + sta = sta_info_get(local, bssid); if (sta) ieee80211_sta_tear_down_BA_sessions(sta); rcu_read_unlock(); - bss = ieee80211_rx_bss_get(local, ifmgd->bssid, - conf->channel->center_freq, - ifmgd->ssid, ifmgd->ssid_len); - - if (bss) - ieee80211_rx_bss_put(local, bss); - - if (self_disconnected) { - if (deauth) - ieee80211_send_deauth_disassoc(sdata, - IEEE80211_STYPE_DEAUTH, reason); - else - ieee80211_send_deauth_disassoc(sdata, - IEEE80211_STYPE_DISASSOC, reason); - } - - ifmgd->flags &= ~IEEE80211_STA_ASSOCIATED; changed |= ieee80211_reset_erp_info(sdata); ieee80211_led_assoc(local, 0); changed |= BSS_CHANGED_ASSOC; sdata->vif.bss_conf.assoc = false; - if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) { - ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_rx_bss_remove(sdata, ifmgd->bssid, - sdata->local->hw.conf.channel->center_freq, - ifmgd->ssid, ifmgd->ssid_len); - } - ieee80211_set_wmm_default(sdata); ieee80211_recalc_idle(local); @@ -1079,7 +1034,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, rcu_read_lock(); - sta = sta_info_get(local, ifmgd->bssid); + sta = sta_info_get(local, bssid); if (!sta) { rcu_read_unlock(); return; @@ -1092,38 +1047,42 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, sta_info_destroy(sta); } -static void ieee80211_associate(struct ieee80211_sub_if_data *sdata) +static enum rx_mgmt_action __must_check +ieee80211_associate(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; - ifmgd->assoc_tries++; - if (ifmgd->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) { + wk->tries++; + if (wk->tries > IEEE80211_ASSOC_MAX_TRIES) { printk(KERN_DEBUG "%s: association with AP %pM" " timed out\n", - sdata->dev->name, ifmgd->bssid); - ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_recalc_idle(local); - cfg80211_send_assoc_timeout(sdata->dev, ifmgd->bssid, - GFP_KERNEL); - ieee80211_rx_bss_remove(sdata, ifmgd->bssid, - sdata->local->hw.conf.channel->center_freq, - ifmgd->ssid, ifmgd->ssid_len); + sdata->dev->name, wk->bss->cbss.bssid); + + /* + * Most likely AP is not in the range so remove the + * bss struct for that AP. + */ + cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss); + /* * We might have a pending scan which had no chance to run yet - * due to state == IEEE80211_STA_MLME_ASSOCIATE. - * Hence, queue the STAs work again + * due to work needing to be done. Hence, queue the STAs work + * again for that. */ queue_work(local->hw.workqueue, &ifmgd->work); - return; + return RX_MGMT_CFG80211_ASSOC_TO; } - ifmgd->state = IEEE80211_STA_MLME_ASSOCIATE; - printk(KERN_DEBUG "%s: associate with AP %pM\n", - sdata->dev->name, ifmgd->bssid); - ieee80211_send_assoc(sdata); + printk(KERN_DEBUG "%s: associate with AP %pM (try %d)\n", + sdata->dev->name, wk->bss->cbss.bssid, wk->tries); + ieee80211_send_assoc(sdata, wk); + + wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; + mod_timer(&ifmgd->timer, wk->timeout); - mod_timer(&ifmgd->timer, jiffies + IEEE80211_ASSOC_TIMEOUT); + return RX_MGMT_NONE; } void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, @@ -1148,6 +1107,7 @@ void ieee80211_beacon_loss_work(struct work_struct *work) container_of(work, struct ieee80211_sub_if_data, u.mgd.beacon_loss_work); struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + const u8 *ssid; /* * The driver has already reported this event and we have @@ -1160,12 +1120,15 @@ void ieee80211_beacon_loss_work(struct work_struct *work) if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) return; + mutex_lock(&ifmgd->mtx); + + if (!ifmgd->associated) + goto out; + #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: driver reports beacon loss from AP %pM " - "- sending probe request\n", sdata->dev->name, - sdata->u.mgd.bssid); - } + if (net_ratelimit()) + printk(KERN_DEBUG "%s: driver reports beacon loss from AP " + "- sending probe request\n", sdata->dev->name); #endif ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; @@ -1174,10 +1137,13 @@ void ieee80211_beacon_loss_work(struct work_struct *work) ieee80211_recalc_ps(sdata->local, -1); mutex_unlock(&sdata->local->iflist_mtx); - ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, - ifmgd->ssid_len, NULL, 0); + ssid = ieee80211_bss_get_ie(&ifmgd->associated->cbss, WLAN_EID_SSID); + ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid, + ssid + 2, ssid[1], NULL, 0); mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT); + out: + mutex_unlock(&ifmgd->mtx); } void ieee80211_beacon_loss(struct ieee80211_vif *vif) @@ -1189,102 +1155,16 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif) } EXPORT_SYMBOL(ieee80211_beacon_loss); -static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) +static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk) { - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_local *local = sdata->local; - struct sta_info *sta; - unsigned long last_rx; - bool disassoc = false; - - /* TODO: start monitoring current AP signal quality and number of - * missed beacons. Scan other channels every now and then and search - * for better APs. */ - /* TODO: remove expired BSSes */ - - ifmgd->state = IEEE80211_STA_MLME_ASSOCIATED; - - rcu_read_lock(); - - sta = sta_info_get(local, ifmgd->bssid); - if (!sta) { - printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n", - sdata->dev->name, ifmgd->bssid); - disassoc = true; - rcu_read_unlock(); - goto out; - } - - last_rx = sta->last_rx; - rcu_read_unlock(); - - if ((ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) && - time_after(jiffies, last_rx + IEEE80211_PROBE_WAIT)) { - printk(KERN_DEBUG "%s: no probe response from AP %pM " - "- disassociating\n", - sdata->dev->name, ifmgd->bssid); - disassoc = true; - ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; - goto out; - } - - /* - * Beacon filtering is only enabled with power save and then the - * stack should not check for beacon loss. - */ - if (!((local->hw.flags & IEEE80211_HW_BEACON_FILTER) && - (local->hw.conf.flags & IEEE80211_CONF_PS)) && - time_after(jiffies, - ifmgd->last_beacon + IEEE80211_MONITORING_INTERVAL)) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: beacon loss from AP %pM " - "- sending probe request\n", - sdata->dev->name, ifmgd->bssid); - } -#endif - ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; - mutex_lock(&local->iflist_mtx); - ieee80211_recalc_ps(local, -1); - mutex_unlock(&local->iflist_mtx); - ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, - ifmgd->ssid_len, NULL, 0); - mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT); - goto out; - } - - if (time_after(jiffies, last_rx + IEEE80211_PROBE_IDLE_TIME)) { - ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; - mutex_lock(&local->iflist_mtx); - ieee80211_recalc_ps(local, -1); - mutex_unlock(&local->iflist_mtx); - ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, - ifmgd->ssid_len, NULL, 0); - } - - out: - if (!disassoc) - mod_timer(&ifmgd->timer, - jiffies + IEEE80211_MONITORING_INTERVAL); - else - ieee80211_set_disassoc(sdata, true, true, - WLAN_REASON_PREV_AUTH_NOT_VALID); -} - - -static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata) -{ - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - + wk->state = IEEE80211_MGD_STATE_IDLE; printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name); - ifmgd->flags |= IEEE80211_STA_AUTHENTICATED; - /* Wait for SME to request association */ - ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_recalc_idle(sdata->local); } static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk, struct ieee80211_mgmt *mgmt, size_t len) { @@ -1295,120 +1175,132 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); if (!elems.challenge) return; - ieee80211_send_auth(sdata, 3, sdata->u.mgd.auth_alg, + ieee80211_send_auth(sdata, 3, wk->auth_alg, elems.challenge - 2, elems.challenge_len + 2, - sdata->u.mgd.bssid, 1); - sdata->u.mgd.auth_transaction = 4; + wk->bss->cbss.bssid, 1); + wk->auth_transaction = 4; } -static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, - struct ieee80211_mgmt *mgmt, - size_t len) +static enum rx_mgmt_action __must_check +ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk, + struct ieee80211_mgmt *mgmt, size_t len) { - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; u16 auth_alg, auth_transaction, status_code; - if (ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE) - return; + if (wk->state != IEEE80211_MGD_STATE_AUTH) + return RX_MGMT_NONE; if (len < 24 + 6) - return; + return RX_MGMT_NONE; - if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN) != 0) - return; + if (memcmp(wk->bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0) + return RX_MGMT_NONE; - if (memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0) - return; + if (memcmp(wk->bss->cbss.bssid, mgmt->bssid, ETH_ALEN) != 0) + return RX_MGMT_NONE; auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); status_code = le16_to_cpu(mgmt->u.auth.status_code); - if (auth_alg != ifmgd->auth_alg || - auth_transaction != ifmgd->auth_transaction) - return; + if (auth_alg != wk->auth_alg || + auth_transaction != wk->auth_transaction) + return RX_MGMT_NONE; if (status_code != WLAN_STATUS_SUCCESS) { - cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len, - GFP_KERNEL); - ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_recalc_idle(sdata->local); - return; + list_del(&wk->list); + kfree(wk); + return RX_MGMT_CFG80211_AUTH; } - switch (ifmgd->auth_alg) { + switch (wk->auth_alg) { case WLAN_AUTH_OPEN: case WLAN_AUTH_LEAP: case WLAN_AUTH_FT: - ieee80211_auth_completed(sdata); - cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len, - GFP_KERNEL); - break; + ieee80211_auth_completed(sdata, wk); + return RX_MGMT_CFG80211_AUTH; case WLAN_AUTH_SHARED_KEY: - if (ifmgd->auth_transaction == 4) { - ieee80211_auth_completed(sdata); - cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len, - GFP_KERNEL); + if (wk->auth_transaction == 4) { + ieee80211_auth_completed(sdata, wk); + return RX_MGMT_CFG80211_AUTH; } else - ieee80211_auth_challenge(sdata, mgmt, len); + ieee80211_auth_challenge(sdata, wk, mgmt, len); break; } + + return RX_MGMT_NONE; } -static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, - struct ieee80211_mgmt *mgmt, - size_t len) +static enum rx_mgmt_action __must_check +ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk, + struct ieee80211_mgmt *mgmt, size_t len) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + const u8 *bssid = NULL; u16 reason_code; if (len < 24 + 2) - return; + return RX_MGMT_NONE; - if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN)) - return; + ASSERT_MGD_MTX(ifmgd); + + if (wk) + bssid = wk->bss->cbss.bssid; + else + bssid = ifmgd->associated->cbss.bssid; reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); - if (ifmgd->flags & IEEE80211_STA_AUTHENTICATED) - printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n", - sdata->dev->name, reason_code); + printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n", + sdata->dev->name, bssid, reason_code); + + if (!wk) { + ieee80211_set_disassoc(sdata, bssid, true); + } else { + list_del(&wk->list); + kfree(wk); + } - ieee80211_set_disassoc(sdata, true, false, 0); - ifmgd->flags &= ~IEEE80211_STA_AUTHENTICATED; - cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, len, GFP_KERNEL); + return RX_MGMT_CFG80211_DEAUTH; } -static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, - struct ieee80211_mgmt *mgmt, - size_t len) +static enum rx_mgmt_action __must_check +ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgmt *mgmt, size_t len) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; u16 reason_code; if (len < 24 + 2) - return; + return RX_MGMT_NONE; - if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN)) - return; + ASSERT_MGD_MTX(ifmgd); + + if (WARN_ON(!ifmgd->associated)) + return RX_MGMT_NONE; + + if (WARN_ON(memcmp(ifmgd->associated->cbss.bssid, mgmt->sa, ETH_ALEN))) + return RX_MGMT_NONE; reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); - if (ifmgd->flags & IEEE80211_STA_ASSOCIATED) - printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", - sdata->dev->name, reason_code); + printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", + sdata->dev->name, reason_code); - ieee80211_set_disassoc(sdata, false, false, reason_code); - cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, len, GFP_KERNEL); + ieee80211_set_disassoc(sdata, ifmgd->associated->cbss.bssid, false); + return RX_MGMT_CFG80211_DISASSOC; } -static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, - struct ieee80211_mgmt *mgmt, - size_t len, - int reassoc) +static enum rx_mgmt_action __must_check +ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk, + struct ieee80211_mgmt *mgmt, size_t len, + bool reassoc) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; @@ -1424,17 +1316,16 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, bool have_higher_than_11mbit = false, newsta = false; u16 ap_ht_cap_flags; - /* AssocResp and ReassocResp have identical structure, so process both - * of them in this function. */ - - if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE) - return; + /* + * AssocResp and ReassocResp have identical structure, so process both + * of them in this function. + */ if (len < 24 + 6) - return; + return RX_MGMT_NONE; - if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN) != 0) - return; + if (memcmp(wk->bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0) + return RX_MGMT_NONE; capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); @@ -1457,21 +1348,19 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: AP rejected association temporarily; " "comeback duration %u TU (%u ms)\n", sdata->dev->name, tu, ms); + wk->timeout = jiffies + msecs_to_jiffies(ms); if (ms > IEEE80211_ASSOC_TIMEOUT) mod_timer(&ifmgd->timer, jiffies + msecs_to_jiffies(ms)); - return; + return RX_MGMT_NONE; } if (status_code != WLAN_STATUS_SUCCESS) { printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", sdata->dev->name, status_code); - cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len, - GFP_KERNEL); - /* Wait for SME to decide what to do next */ - ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_recalc_idle(local); - return; + list_del(&wk->list); + kfree(wk); + return RX_MGMT_CFG80211_ASSOC; } if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) @@ -1482,50 +1371,38 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, if (!elems.supp_rates) { printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n", sdata->dev->name); - return; + return RX_MGMT_NONE; } printk(KERN_DEBUG "%s: associated\n", sdata->dev->name); ifmgd->aid = aid; - kfree(ifmgd->assocresp_ies); - ifmgd->assocresp_ies_len = len - (pos - (u8 *) mgmt); - ifmgd->assocresp_ies = kmalloc(ifmgd->assocresp_ies_len, GFP_KERNEL); - if (ifmgd->assocresp_ies) - memcpy(ifmgd->assocresp_ies, pos, ifmgd->assocresp_ies_len); - rcu_read_lock(); /* Add STA entry for the AP */ - sta = sta_info_get(local, ifmgd->bssid); + sta = sta_info_get(local, wk->bss->cbss.bssid); if (!sta) { newsta = true; - sta = sta_info_alloc(sdata, ifmgd->bssid, GFP_ATOMIC); + rcu_read_unlock(); + + sta = sta_info_alloc(sdata, wk->bss->cbss.bssid, GFP_KERNEL); if (!sta) { printk(KERN_DEBUG "%s: failed to alloc STA entry for" " the AP\n", sdata->dev->name); - rcu_read_unlock(); - return; + return RX_MGMT_NONE; } /* update new sta with its last rx activity */ sta->last_rx = jiffies; - } - /* - * FIXME: Do we really need to update the sta_info's information here? - * We already know about the AP (we found it in our list) so it - * should already be filled with the right info, no? - * As is stands, all this is racy because typically we assume - * the information that is filled in here (except flags) doesn't - * change while a STA structure is alive. As such, it should move - * to between the sta_info_alloc() and sta_info_insert() above. - */ + set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | + WLAN_STA_ASSOC_AP); + if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) + set_sta_flags(sta, WLAN_STA_AUTHORIZED); - set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP); - if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) - set_sta_flags(sta, WLAN_STA_AUTHORIZED); + rcu_read_lock(); + } rates = 0; basic_rates = 0; @@ -1595,7 +1472,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: failed to insert STA entry for" " the AP (error %d)\n", sdata->dev->name, err); rcu_read_unlock(); - return; + return RX_MGMT_NONE; } } @@ -1611,13 +1488,14 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, + wk->bss->cbss.bssid, ap_ht_cap_flags); /* set AID and assoc capability, * ieee80211_set_associated() will tell the driver */ bss_conf->aid = aid; bss_conf->assoc_capability = capab_info; - ieee80211_set_associated(sdata, changed); + ieee80211_set_associated(sdata, wk->bss, changed); /* * initialise the time of last beacon to be the association time, @@ -1625,8 +1503,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, */ ifmgd->last_beacon = jiffies; - ieee80211_associated(sdata); - cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len, GFP_KERNEL); + list_del(&wk->list); + kfree(wk); + return RX_MGMT_CFG80211_ASSOC; } @@ -1654,23 +1533,25 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, channel, beacon); - if (!bss) + if (bss) + ieee80211_rx_bss_put(local, bss); + + if (!sdata->u.mgd.associated) return; if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) && - (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN) == 0)) { + (memcmp(mgmt->bssid, sdata->u.mgd.associated->cbss.bssid, + ETH_ALEN) == 0)) { struct ieee80211_channel_sw_ie *sw_elem = (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; ieee80211_sta_process_chanswitch(sdata, sw_elem, bss); } - - ieee80211_rx_bss_put(local, bss); } static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, - struct ieee80211_mgmt *mgmt, - size_t len, + struct ieee80211_mgd_work *wk, + struct ieee80211_mgmt *mgmt, size_t len, struct ieee80211_rx_status *rx_status) { struct ieee80211_if_managed *ifmgd; @@ -1679,6 +1560,8 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, ifmgd = &sdata->u.mgd; + ASSERT_MGD_MTX(ifmgd); + if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) return; /* ignore ProbeResp to foreign address */ @@ -1692,13 +1575,17 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); /* direct probe may be part of the association flow */ - if (ifmgd->state == IEEE80211_STA_MLME_DIRECT_PROBE) { + if (wk && wk->state == IEEE80211_MGD_STATE_PROBE) { printk(KERN_DEBUG "%s direct probe responded\n", sdata->dev->name); - ieee80211_authenticate(sdata); + wk->tries = 0; + wk->state = IEEE80211_MGD_STATE_AUTH; + WARN_ON(ieee80211_authenticate(sdata, wk) != RX_MGMT_NONE); } - if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) { + if (ifmgd->associated && + memcmp(mgmt->bssid, ifmgd->associated->cbss.bssid, ETH_ALEN) == 0 && + ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) { ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; mutex_lock(&sdata->local->iflist_mtx); ieee80211_recalc_ps(sdata->local, -1); @@ -1740,6 +1627,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, bool erp_valid, directed_tim = false; u8 erp_value = 0; u32 ncrc; + u8 *bssid; + + ASSERT_MGD_MTX(ifmgd); /* Process beacon from the current BSS */ baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; @@ -1749,8 +1639,12 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, if (rx_status->freq != local->hw.conf.channel->center_freq) return; - if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED) || - memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0) + if (WARN_ON(!ifmgd->associated)) + return; + + bssid = ifmgd->associated->cbss.bssid; + + if (WARN_ON(memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0)) return; if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) { @@ -1829,8 +1723,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, rcu_read_lock(); - sta = sta_info_get(local, ifmgd->bssid); - if (!sta) { + sta = sta_info_get(local, bssid); + if (WARN_ON(!sta)) { rcu_read_unlock(); return; } @@ -1845,7 +1739,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, rcu_read_unlock(); changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, - ap_ht_cap_flags); + bssid, ap_ht_cap_flags); } if (elems.country_elem) { @@ -1887,6 +1781,7 @@ ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, case IEEE80211_STYPE_REASSOC_RESP: case IEEE80211_STYPE_DEAUTH: case IEEE80211_STYPE_DISASSOC: + case IEEE80211_STYPE_ACTION: skb_queue_tail(&sdata->u.mgd.skb_queue, skb); queue_work(local->hw.workqueue, &sdata->u.mgd.work); return RX_QUEUED; @@ -1898,40 +1793,118 @@ ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_rx_status *rx_status; struct ieee80211_mgmt *mgmt; + struct ieee80211_mgd_work *wk; + enum rx_mgmt_action rma = RX_MGMT_NONE; u16 fc; rx_status = (struct ieee80211_rx_status *) skb->cb; mgmt = (struct ieee80211_mgmt *) skb->data; fc = le16_to_cpu(mgmt->frame_control); - switch (fc & IEEE80211_FCTL_STYPE) { - case IEEE80211_STYPE_PROBE_RESP: - ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, - rx_status); - break; - case IEEE80211_STYPE_BEACON: - ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, - rx_status); - break; - case IEEE80211_STYPE_AUTH: - ieee80211_rx_mgmt_auth(sdata, mgmt, skb->len); - break; - case IEEE80211_STYPE_ASSOC_RESP: - ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, 0); + mutex_lock(&ifmgd->mtx); + + if (ifmgd->associated && + memcmp(ifmgd->associated->cbss.bssid, mgmt->bssid, + ETH_ALEN) == 0) { + switch (fc & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_BEACON: + ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, + rx_status); + break; + case IEEE80211_STYPE_PROBE_RESP: + ieee80211_rx_mgmt_probe_resp(sdata, NULL, mgmt, + skb->len, rx_status); + break; + case IEEE80211_STYPE_DEAUTH: + rma = ieee80211_rx_mgmt_deauth(sdata, NULL, + mgmt, skb->len); + break; + case IEEE80211_STYPE_DISASSOC: + rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); + break; + case IEEE80211_STYPE_ACTION: + /* XXX: differentiate, can only happen for CSA now! */ + ieee80211_sta_process_chanswitch(sdata, + &mgmt->u.action.u.chan_switch.sw_elem, + ifmgd->associated); + break; + } + mutex_unlock(&ifmgd->mtx); + + switch (rma) { + case RX_MGMT_NONE: + /* no action */ + break; + case RX_MGMT_CFG80211_DEAUTH: + cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, + skb->len, GFP_KERNEL); + break; + case RX_MGMT_CFG80211_DISASSOC: + cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, + skb->len, GFP_KERNEL); + break; + default: + WARN(1, "unexpected: %d", rma); + } + goto out; + } + + list_for_each_entry(wk, &ifmgd->work_list, list) { + if (memcmp(wk->bss->cbss.bssid, mgmt->bssid, ETH_ALEN) != 0) + continue; + + switch (fc & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_PROBE_RESP: + ieee80211_rx_mgmt_probe_resp(sdata, wk, mgmt, skb->len, + rx_status); + break; + case IEEE80211_STYPE_AUTH: + rma = ieee80211_rx_mgmt_auth(sdata, wk, mgmt, skb->len); + break; + case IEEE80211_STYPE_ASSOC_RESP: + rma = ieee80211_rx_mgmt_assoc_resp(sdata, wk, mgmt, + skb->len, false); + break; + case IEEE80211_STYPE_REASSOC_RESP: + rma = ieee80211_rx_mgmt_assoc_resp(sdata, wk, mgmt, + skb->len, true); + break; + case IEEE80211_STYPE_DEAUTH: + rma = ieee80211_rx_mgmt_deauth(sdata, wk, mgmt, + skb->len); + break; + } + /* + * We've processed this frame for that work, so it can't + * belong to another work struct. + * NB: this is also required for correctness because the + * called functions can free 'wk', and for 'rma'! + */ break; - case IEEE80211_STYPE_REASSOC_RESP: - ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, 1); + } + + mutex_unlock(&ifmgd->mtx); + + switch (rma) { + case RX_MGMT_NONE: + /* no action */ break; - case IEEE80211_STYPE_DEAUTH: - ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len); + case RX_MGMT_CFG80211_AUTH: + cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, skb->len, + GFP_KERNEL); break; - case IEEE80211_STYPE_DISASSOC: - ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); + case RX_MGMT_CFG80211_ASSOC: + cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, skb->len, + GFP_KERNEL); break; + default: + WARN(1, "unexpected: %d", rma); } + out: kfree_skb(skb); } @@ -1947,89 +1920,9 @@ static void ieee80211_sta_timer(unsigned long data) return; } - set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); queue_work(local->hw.workqueue, &ifmgd->work); } -static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata) -{ - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_local *local = sdata->local; - - /* Reset own TSF to allow time synchronization work. */ - drv_reset_tsf(local); - - ifmgd->wmm_last_param_set = -1; /* allow any WMM update */ - ifmgd->auth_transaction = -1; - ifmgd->flags &= ~IEEE80211_STA_ASSOCIATED; - ifmgd->assoc_scan_tries = 0; - ifmgd->direct_probe_tries = 0; - ifmgd->auth_tries = 0; - ifmgd->assoc_tries = 0; - netif_tx_stop_all_queues(sdata->dev); - netif_carrier_off(sdata->dev); -} - -static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata) -{ - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_local *local = sdata->local; - struct ieee80211_bss *bss; - u8 *bssid = ifmgd->bssid, *ssid = ifmgd->ssid; - u8 ssid_len = ifmgd->ssid_len; - u16 capa_mask = WLAN_CAPABILITY_ESS; - u16 capa_val = WLAN_CAPABILITY_ESS; - struct ieee80211_channel *chan = local->oper_channel; - - bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan, - bssid, ssid, ssid_len, - capa_mask, capa_val); - - if (bss) { - local->oper_channel = bss->cbss.channel; - local->oper_channel_type = NL80211_CHAN_NO_HT; - ieee80211_hw_config(local, 0); - - ieee80211_sta_def_wmm_params(sdata, bss->supp_rates_len, - bss->supp_rates); - if (sdata->u.mgd.mfp == IEEE80211_MFP_REQUIRED) - sdata->u.mgd.flags |= IEEE80211_STA_MFP_ENABLED; - else - sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED; - - /* Send out direct probe if no probe resp was received or - * the one we have is outdated - */ - if (!bss->last_probe_resp || - time_after(jiffies, bss->last_probe_resp - + IEEE80211_SCAN_RESULT_EXPIRE)) - ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE; - else - ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE; - - ieee80211_rx_bss_put(local, bss); - ieee80211_sta_reset_auth(sdata); - return 0; - } else { - if (ifmgd->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) { - - ifmgd->assoc_scan_tries++; - - ieee80211_request_internal_scan(sdata, ifmgd->ssid, - ssid_len); - - ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE; - set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request); - } else { - ifmgd->assoc_scan_tries = 0; - ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_recalc_idle(local); - } - } - return -1; -} - - static void ieee80211_sta_work(struct work_struct *work) { struct ieee80211_sub_if_data *sdata = @@ -2037,6 +1930,10 @@ static void ieee80211_sta_work(struct work_struct *work) struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd; struct sk_buff *skb; + struct ieee80211_mgd_work *wk, *tmp; + LIST_HEAD(free_work); + enum rx_mgmt_action rma; + bool anybusy = false; if (!netif_running(sdata->dev)) return; @@ -2059,46 +1956,93 @@ static void ieee80211_sta_work(struct work_struct *work) ifmgd = &sdata->u.mgd; + /* first process frames to avoid timing out while a frame is pending */ while ((skb = skb_dequeue(&ifmgd->skb_queue))) ieee80211_sta_rx_queued_mgmt(sdata, skb); - if (ifmgd->state != IEEE80211_STA_MLME_DIRECT_PROBE && - ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE && - ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE && - test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) { - queue_delayed_work(local->hw.workqueue, &local->scan_work, - round_jiffies_relative(0)); - return; + /* then process the rest of the work */ + mutex_lock(&ifmgd->mtx); + + list_for_each_entry(wk, &ifmgd->work_list, list) { + if (wk->state != IEEE80211_MGD_STATE_IDLE) { + anybusy = true; + break; + } } - if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request)) { - if (ieee80211_sta_config_auth(sdata)) - return; - clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); - } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request)) + ieee80211_recalc_idle(local); + + if (!anybusy) { + mutex_unlock(&ifmgd->mtx); + + if (test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) + queue_delayed_work(local->hw.workqueue, + &local->scan_work, + round_jiffies_relative(0)); return; + } - ieee80211_recalc_idle(local); + list_for_each_entry_safe(wk, tmp, &ifmgd->work_list, list) { + if (time_before(jiffies, wk->timeout)) + continue; - switch (ifmgd->state) { - case IEEE80211_STA_MLME_DISABLED: - break; - case IEEE80211_STA_MLME_DIRECT_PROBE: - ieee80211_direct_probe(sdata); - break; - case IEEE80211_STA_MLME_AUTHENTICATE: - ieee80211_authenticate(sdata); - break; - case IEEE80211_STA_MLME_ASSOCIATE: - ieee80211_associate(sdata); - break; - case IEEE80211_STA_MLME_ASSOCIATED: - ieee80211_associated(sdata); - break; - default: - WARN_ON(1); - break; + switch (wk->state) { + default: + WARN_ON(1); + /* fall through */ + case IEEE80211_MGD_STATE_IDLE: + /* nothing */ + rma = RX_MGMT_NONE; + break; + case IEEE80211_MGD_STATE_PROBE: + rma = ieee80211_direct_probe(sdata, wk); + break; + case IEEE80211_MGD_STATE_AUTH: + rma = ieee80211_authenticate(sdata, wk); + break; + case IEEE80211_MGD_STATE_ASSOC: + rma = ieee80211_associate(sdata, wk); + break; + } + + switch (rma) { + case RX_MGMT_NONE: + /* no action required */ + break; + case RX_MGMT_CFG80211_AUTH_TO: + case RX_MGMT_CFG80211_ASSOC_TO: + list_del(&wk->list); + list_add(&wk->list, &free_work); + wk->tries = rma; /* small abuse but only local */ + break; + default: + WARN(1, "unexpected: %d", rma); + } + } + + mutex_unlock(&ifmgd->mtx); + + list_for_each_entry_safe(wk, tmp, &free_work, list) { + switch (wk->tries) { + case RX_MGMT_CFG80211_AUTH_TO: + cfg80211_send_auth_timeout(sdata->dev, + wk->bss->cbss.bssid, + GFP_KERNEL); + break; + case RX_MGMT_CFG80211_ASSOC_TO: + cfg80211_send_auth_timeout(sdata->dev, + wk->bss->cbss.bssid, + GFP_KERNEL); + break; + default: + WARN(1, "unexpected: %d", wk->tries); + } + + list_del(&wk->list); + kfree(wk); } + + ieee80211_recalc_idle(local); } static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) @@ -2110,7 +2054,6 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) */ sdata->u.mgd.last_beacon = jiffies; - queue_work(sdata->local->hw.workqueue, &sdata->u.mgd.work); } @@ -2152,7 +2095,6 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_managed *ifmgd; - u32 hw_flags; ifmgd = &sdata->u.mgd; INIT_WORK(&ifmgd->work, ieee80211_sta_work); @@ -2164,113 +2106,239 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) (unsigned long) sdata); skb_queue_head_init(&ifmgd->skb_queue); + INIT_LIST_HEAD(&ifmgd->work_list); + ifmgd->capab = WLAN_CAPABILITY_ESS; ifmgd->flags = 0; if (sdata->local->hw.queues >= 4) ifmgd->flags |= IEEE80211_STA_WMM_ENABLED; - hw_flags = sdata->local->hw.flags; + mutex_init(&ifmgd->mtx); } -/* configuration hooks */ -void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata) +/* scan finished notification */ +void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) { - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_local *local = sdata->local; + struct ieee80211_sub_if_data *sdata = local->scan_sdata; - if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) - return; + /* Restart STA timers */ + rcu_read_lock(); + list_for_each_entry_rcu(sdata, &local->interfaces, list) + ieee80211_restart_sta_timer(sdata); + rcu_read_unlock(); +} - if (WARN_ON(ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED)) - ieee80211_set_disassoc(sdata, true, true, - WLAN_REASON_DEAUTH_LEAVING); +int ieee80211_max_network_latency(struct notifier_block *nb, + unsigned long data, void *dummy) +{ + s32 latency_usec = (s32) data; + struct ieee80211_local *local = + container_of(nb, struct ieee80211_local, + network_latency_notifier); - if (WARN_ON(ifmgd->ssid_len == 0)) { - /* - * Only allow association to be started if a valid SSID - * is configured. - */ - return; - } + mutex_lock(&local->iflist_mtx); + ieee80211_recalc_ps(local, latency_usec); + mutex_unlock(&local->iflist_mtx); - set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); - queue_work(local->hw.workqueue, &ifmgd->work); + return 0; } -int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, - const char *ie, size_t len) +/* config hooks */ +int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, + struct cfg80211_auth_request *req) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + const u8 *ssid; + struct ieee80211_mgd_work *wk; + u16 auth_alg; - if (len == 0 && ifmgd->extra_ie_len == 0) - return -EALREADY; - - if (len == ifmgd->extra_ie_len && ifmgd->extra_ie && - memcmp(ifmgd->extra_ie, ie, len) == 0) - return -EALREADY; - - kfree(ifmgd->extra_ie); - if (len == 0) { - ifmgd->extra_ie = NULL; - ifmgd->extra_ie_len = 0; - return 0; + switch (req->auth_type) { + case NL80211_AUTHTYPE_OPEN_SYSTEM: + auth_alg = WLAN_AUTH_OPEN; + break; + case NL80211_AUTHTYPE_SHARED_KEY: + auth_alg = WLAN_AUTH_SHARED_KEY; + break; + case NL80211_AUTHTYPE_FT: + auth_alg = WLAN_AUTH_FT; + break; + case NL80211_AUTHTYPE_NETWORK_EAP: + auth_alg = WLAN_AUTH_LEAP; + break; + default: + return -EOPNOTSUPP; } - ifmgd->extra_ie = kmalloc(len, GFP_KERNEL); - if (!ifmgd->extra_ie) { - ifmgd->extra_ie_len = 0; + + wk = kzalloc(sizeof(*wk) + req->ie_len, GFP_KERNEL); + if (!wk) return -ENOMEM; + + wk->bss = (void *)req->bss; + + if (req->ie && req->ie_len) { + memcpy(wk->ie, req->ie, req->ie_len); + wk->ie_len = req->ie_len; } - memcpy(ifmgd->extra_ie, ie, len); - ifmgd->extra_ie_len = len; + + ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); + memcpy(wk->ssid, ssid + 2, ssid[1]); + wk->ssid_len = ssid[1]; + + wk->state = IEEE80211_MGD_STATE_PROBE; + wk->auth_alg = auth_alg; + + /* + * XXX: if still associated need to tell AP that we're going + * to sleep and then change channel etc. + */ + sdata->local->oper_channel = req->bss->channel; + ieee80211_hw_config(sdata->local, 0); + + mutex_lock(&ifmgd->mtx); + list_add(&wk->list, &sdata->u.mgd.work_list); + mutex_unlock(&ifmgd->mtx); + + queue_work(sdata->local->hw.workqueue, &sdata->u.mgd.work); return 0; } -int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason) +int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, + struct cfg80211_assoc_request *req) { - printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n", - sdata->dev->name, reason); + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_mgd_work *wk, *found = NULL; + int i, err; - ieee80211_set_disassoc(sdata, true, true, reason); - return 0; + mutex_lock(&ifmgd->mtx); + + list_for_each_entry(wk, &ifmgd->work_list, list) { + if (&wk->bss->cbss == req->bss && + wk->state == IEEE80211_MGD_STATE_IDLE) { + found = wk; + break; + } + } + + if (!found) { + err = -ENOLINK; + goto out; + } + + list_del(&found->list); + + wk = krealloc(found, sizeof(*wk) + req->ie_len, GFP_KERNEL); + if (!wk) { + list_add(&found->list, &ifmgd->work_list); + err = -ENOMEM; + goto out; + } + + list_add(&wk->list, &ifmgd->work_list); + + ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; + + for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) + if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || + req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || + req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) + ifmgd->flags |= IEEE80211_STA_DISABLE_11N; + + sdata->local->oper_channel = req->bss->channel; + ieee80211_hw_config(sdata->local, 0); + + if (req->ie && req->ie_len) { + memcpy(wk->ie, req->ie, req->ie_len); + wk->ie_len = req->ie_len; + } else + wk->ie_len = 0; + + if (req->prev_bssid) + memcpy(wk->prev_bssid, req->prev_bssid, ETH_ALEN); + + wk->state = IEEE80211_MGD_STATE_ASSOC; + wk->tries = 0; + + if (req->use_mfp) { + ifmgd->mfp = IEEE80211_MFP_REQUIRED; + ifmgd->flags |= IEEE80211_STA_MFP_ENABLED; + } else { + ifmgd->mfp = IEEE80211_MFP_DISABLED; + ifmgd->flags &= ~IEEE80211_STA_MFP_ENABLED; + } + + if (req->crypto.control_port) + ifmgd->flags |= IEEE80211_STA_CONTROL_PORT; + else + ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT; + + queue_work(sdata->local->hw.workqueue, &sdata->u.mgd.work); + + err = 0; + + out: + mutex_unlock(&ifmgd->mtx); + return err; } -int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason) +int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, + struct cfg80211_deauth_request *req) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_mgd_work *wk; + const u8 *bssid = NULL; - printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n", - sdata->dev->name, reason); + printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n", + sdata->dev->name, req->reason_code); + + mutex_lock(&ifmgd->mtx); + + if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) { + bssid = req->bss->bssid; + ieee80211_set_disassoc(sdata, bssid, true); + } else list_for_each_entry(wk, &ifmgd->work_list, list) { + if (&wk->bss->cbss == req->bss) { + bssid = req->bss->bssid; + list_del(&wk->list); + kfree(wk); + break; + } + } - if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED)) + /* cfg80211 should catch this... */ + if (WARN_ON(!bssid)) { + mutex_unlock(&ifmgd->mtx); return -ENOLINK; + } + + mutex_unlock(&ifmgd->mtx); + + ieee80211_send_deauth_disassoc(sdata, bssid, + IEEE80211_STYPE_DEAUTH, req->reason_code); - ieee80211_set_disassoc(sdata, false, true, reason); return 0; } -/* scan finished notification */ -void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) +int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, + struct cfg80211_disassoc_request *req) { - struct ieee80211_sub_if_data *sdata = local->scan_sdata; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - /* Restart STA timers */ - rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, list) - ieee80211_restart_sta_timer(sdata); - rcu_read_unlock(); -} + printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n", + sdata->dev->name, req->reason_code); -int ieee80211_max_network_latency(struct notifier_block *nb, - unsigned long data, void *dummy) -{ - s32 latency_usec = (s32) data; - struct ieee80211_local *local = - container_of(nb, struct ieee80211_local, - network_latency_notifier); + mutex_lock(&ifmgd->mtx); - mutex_lock(&local->iflist_mtx); - ieee80211_recalc_ps(local, latency_usec); - mutex_unlock(&local->iflist_mtx); + /* cfg80211 should catch that */ + if (WARN_ON(&ifmgd->associated->cbss != req->bss)) { + mutex_unlock(&ifmgd->mtx); + return -ENOLINK; + } + + ieee80211_set_disassoc(sdata, req->bss->bssid, false); + + mutex_unlock(&ifmgd->mtx); + ieee80211_send_deauth_disassoc(sdata, req->bss->bssid, + IEEE80211_STYPE_DISASSOC, req->reason_code); return 0; } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index ec5acc6dc021..fe6b99059531 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1641,12 +1641,7 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata, if (compare_ether_addr(mgmt->sa, sdata->u.mgd.bssid) != 0 || compare_ether_addr(mgmt->bssid, sdata->u.mgd.bssid) != 0) { - /* Not from the current AP. */ - return; - } - - if (sdata->u.mgd.state == IEEE80211_STA_MLME_ASSOCIATE) { - /* Association in progress; ignore SA Query */ + /* Not from the current AP or not associated yet. */ return; } @@ -1683,7 +1678,6 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) struct ieee80211_local *local = rx->local; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; - struct ieee80211_bss *bss; int len = rx->skb->len; if (!ieee80211_is_action(mgmt->frame_control)) @@ -1761,17 +1755,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN)) return RX_DROP_MONITOR; - bss = ieee80211_rx_bss_get(local, sdata->u.mgd.bssid, - local->hw.conf.channel->center_freq, - sdata->u.mgd.ssid, - sdata->u.mgd.ssid_len); - if (!bss) - return RX_DROP_MONITOR; - - ieee80211_sta_process_chanswitch(sdata, - &mgmt->u.action.u.chan_switch.sw_elem, bss); - ieee80211_rx_bss_put(local, bss); - break; + return ieee80211_sta_rx_mgmt(sdata, rx->skb); } break; case WLAN_CATEGORY_SA_QUERY: @@ -2026,13 +2010,8 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, case NL80211_IFTYPE_STATION: if (!bssid) return 0; - if (!ieee80211_bssid_match(bssid, sdata->u.mgd.bssid)) { - if (!(rx->flags & IEEE80211_RX_IN_SCAN)) - return 0; - rx->flags &= ~IEEE80211_RX_RA_MATCH; - } else if (!multicast && - compare_ether_addr(sdata->dev->dev_addr, - hdr->addr1) != 0) { + if (!multicast && + compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { if (!(sdata->dev->flags & IFF_PROMISC)) return 0; rx->flags &= ~IEEE80211_RX_RA_MATCH; diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 569a464f60d8..5f4f7869d050 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -121,19 +121,6 @@ ieee80211_bss_info_update(struct ieee80211_local *local, return bss; } -void ieee80211_rx_bss_remove(struct ieee80211_sub_if_data *sdata, u8 *bssid, - int freq, u8 *ssid, u8 ssid_len) -{ - struct ieee80211_bss *bss; - struct ieee80211_local *local = sdata->local; - - bss = ieee80211_rx_bss_get(local, bssid, freq, ssid, ssid_len); - if (bss) { - cfg80211_unlink_bss(local->hw.wiphy, (void *)bss); - ieee80211_rx_bss_put(local, bss); - } -} - ieee80211_rx_result ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { @@ -327,7 +314,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) /* Tell AP we're back */ if (sdata->vif.type == NL80211_IFTYPE_STATION) { - if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) { + if (sdata->u.mgd.associated) { ieee80211_scan_ps_disable(sdata); netif_tx_wake_all_queues(sdata->dev); } @@ -383,7 +370,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) sdata, BSS_CHANGED_BEACON_ENABLED); if (sdata->vif.type == NL80211_IFTYPE_STATION) { - if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) { + if (sdata->u.mgd.associated) { netif_tx_stop_all_queues(sdata->dev); ieee80211_scan_ps_enable(sdata); } @@ -443,10 +430,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, if (req != &local->int_scan_req && sdata->vif.type == NL80211_IFTYPE_STATION && - (ifmgd->state == IEEE80211_STA_MLME_DIRECT_PROBE || - ifmgd->state == IEEE80211_STA_MLME_AUTHENTICATE || - ifmgd->state == IEEE80211_STA_MLME_ASSOCIATE)) { - /* actually wait for the assoc to finish/time out */ + !list_empty(&ifmgd->work_list)) { + /* actually wait for the work it's doing to finish/time out */ set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request); return 0; } -- cgit v1.2.3 From c9cf01226e0bd1fa4f7f7024d8d53e982fad208f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jul 2009 03:45:18 +0200 Subject: mac80211: refactor the WEP code to be directly usable The new key work for cfg80211 will only give us the WEP key for shared auth to do that authentication, and not via the regular key settings, so we need to be able to encrypt a single frame in software, and that without a key struct. Thus, refactor the WEP code to not require a key structure but use the key, len and idx directly. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/wep.c | 52 +++++++++++++++++++++++----------------------------- net/mac80211/wep.h | 4 ---- 2 files changed, 23 insertions(+), 33 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index ef73105b3061..4fafb2d27c84 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -67,10 +67,10 @@ static inline bool ieee80211_wep_weak_iv(u32 iv, int keylen) static void ieee80211_wep_get_iv(struct ieee80211_local *local, - struct ieee80211_key *key, u8 *iv) + int keylen, int keyidx, u8 *iv) { local->wep_iv++; - if (ieee80211_wep_weak_iv(local->wep_iv, key->conf.keylen)) + if (ieee80211_wep_weak_iv(local->wep_iv, keylen)) local->wep_iv += 0x0100; if (!iv) @@ -79,13 +79,13 @@ static void ieee80211_wep_get_iv(struct ieee80211_local *local, *iv++ = (local->wep_iv >> 16) & 0xff; *iv++ = (local->wep_iv >> 8) & 0xff; *iv++ = local->wep_iv & 0xff; - *iv++ = key->conf.keyidx << 6; + *iv++ = keyidx << 6; } static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local, struct sk_buff *skb, - struct ieee80211_key *key) + int keylen, int keyidx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; unsigned int hdrlen; @@ -100,7 +100,7 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local, hdrlen = ieee80211_hdrlen(hdr->frame_control); newhdr = skb_push(skb, WEP_IV_LEN); memmove(newhdr, newhdr + WEP_IV_LEN, hdrlen); - ieee80211_wep_get_iv(local, key, newhdr + hdrlen); + ieee80211_wep_get_iv(local, keylen, keyidx, newhdr + hdrlen); return newhdr + hdrlen; } @@ -144,26 +144,17 @@ void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, * * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data)) */ -int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb, - struct ieee80211_key *key) +static int ieee80211_wep_encrypt(struct ieee80211_local *local, + struct sk_buff *skb, + const u8 *key, int keylen, int keyidx) { - u32 klen; - u8 *rc4key, *iv; + u8 *iv; size_t len; + u8 rc4key[3 + WLAN_KEY_LEN_WEP104]; - if (!key || key->conf.alg != ALG_WEP) - return -1; - - klen = 3 + key->conf.keylen; - rc4key = kmalloc(klen, GFP_ATOMIC); - if (!rc4key) - return -1; - - iv = ieee80211_wep_add_iv(local, skb, key); - if (!iv) { - kfree(rc4key); + iv = ieee80211_wep_add_iv(local, skb, keylen, keyidx); + if (!iv) return -1; - } len = skb->len - (iv + WEP_IV_LEN - skb->data); @@ -171,16 +162,14 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb, memcpy(rc4key, iv, 3); /* Copy rest of the WEP key (the secret part) */ - memcpy(rc4key + 3, key->conf.key, key->conf.keylen); + memcpy(rc4key + 3, key, keylen); /* Add room for ICV */ skb_put(skb, WEP_ICV_LEN); - ieee80211_wep_encrypt_data(local->wep_tx_tfm, rc4key, klen, + ieee80211_wep_encrypt_data(local->wep_tx_tfm, rc4key, keylen + 3, iv + WEP_IV_LEN, len); - kfree(rc4key); - return 0; } @@ -216,8 +205,9 @@ int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, * failure. If frame is OK, IV and ICV will be removed, i.e., decrypted payload * is moved to the beginning of the skb and skb length will be reduced. */ -int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb, - struct ieee80211_key *key) +static int ieee80211_wep_decrypt(struct ieee80211_local *local, + struct sk_buff *skb, + struct ieee80211_key *key) { u32 klen; u8 *rc4key; @@ -314,12 +304,16 @@ static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { - if (ieee80211_wep_encrypt(tx->local, skb, tx->key)) + if (ieee80211_wep_encrypt(tx->local, skb, tx->key->conf.key, + tx->key->conf.keylen, + tx->key->conf.keyidx)) return -1; } else { info->control.hw_key = &tx->key->conf; if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) { - if (!ieee80211_wep_add_iv(tx->local, skb, tx->key)) + if (!ieee80211_wep_add_iv(tx->local, skb, + tx->key->conf.keylen, + tx->key->conf.keyidx)) return -1; } } diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h index d3f0db48314e..85219ded8703 100644 --- a/net/mac80211/wep.h +++ b/net/mac80211/wep.h @@ -22,10 +22,6 @@ void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, size_t klen, u8 *data, size_t data_len); int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, size_t klen, u8 *data, size_t data_len); -int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb, - struct ieee80211_key *key); -int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb, - struct ieee80211_key *key); bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key); ieee80211_rx_result -- cgit v1.2.3 From cb0b4beb93d14429bf0c50fc1ab8e26348dca880 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jul 2009 03:56:07 +0200 Subject: cfg80211: mlme API must be able to sleep After the mac80211 mlme cleanup, we can require that the MLME functions in cfg80211 can sleep. This will simplify future work in cfg80211 a lot. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 108e8c9c60fd..15dbb57ab55e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -412,11 +412,9 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, mgmt->u.deauth.reason_code = cpu_to_le16(reason); if (stype == IEEE80211_STYPE_DEAUTH) - cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, skb->len, - GFP_KERNEL); + cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, skb->len); else - cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, skb->len, - GFP_KERNEL); + cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, skb->len); ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED); } @@ -1839,12 +1837,10 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, /* no action */ break; case RX_MGMT_CFG80211_DEAUTH: - cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, - skb->len, GFP_KERNEL); + cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); break; case RX_MGMT_CFG80211_DISASSOC: - cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, - skb->len, GFP_KERNEL); + cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len); break; default: WARN(1, "unexpected: %d", rma); @@ -1893,12 +1889,10 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, /* no action */ break; case RX_MGMT_CFG80211_AUTH: - cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, skb->len, - GFP_KERNEL); + cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, skb->len); break; case RX_MGMT_CFG80211_ASSOC: - cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, skb->len, - GFP_KERNEL); + cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, skb->len); break; default: WARN(1, "unexpected: %d", rma); @@ -2026,13 +2020,11 @@ static void ieee80211_sta_work(struct work_struct *work) switch (wk->tries) { case RX_MGMT_CFG80211_AUTH_TO: cfg80211_send_auth_timeout(sdata->dev, - wk->bss->cbss.bssid, - GFP_KERNEL); + wk->bss->cbss.bssid); break; case RX_MGMT_CFG80211_ASSOC_TO: - cfg80211_send_auth_timeout(sdata->dev, - wk->bss->cbss.bssid, - GFP_KERNEL); + cfg80211_send_assoc_timeout(sdata->dev, + wk->bss->cbss.bssid); break; default: WARN(1, "unexpected: %d", wk->tries); -- cgit v1.2.3 From 667503ddcb96f3b10211f997fe55907fa7509841 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jul 2009 03:56:11 +0200 Subject: cfg80211: fix locking Over time, a lot of locking issues have crept into the smarts of cfg80211, so e.g. scan completion can race against a new scan, IBSS join can race against leaving an IBSS, etc. Introduce a new per-interface lock that protects most of the per-interface data that we need to keep track of, and sprinkle assertions about that lock everywhere. Some things now need to be offloaded to work structs so that we don't require being able to sleep in functions the drivers call. The exception to that are the MLME callbacks (rx_auth etc.) that currently only mac80211 calls because it was easier to do that there instead of in cfg80211, and future drivers implementing those calls will, if they ever exist, probably need to use a similar scheme like mac80211 anyway... In order to be able to handle _deauth and _disassoc properly, introduce a cookie passed to it that will determine locking requirements. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 12 ++++++++---- net/mac80211/ieee80211_i.h | 6 ++++-- net/mac80211/mlme.c | 25 ++++++++++++++++--------- 3 files changed, 28 insertions(+), 15 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 7cfc14e4ca07..36f8f245fa4c 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1182,15 +1182,19 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, } static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_deauth_request *req) + struct cfg80211_deauth_request *req, + void *cookie) { - return ieee80211_mgd_deauth(IEEE80211_DEV_TO_SUB_IF(dev), req); + return ieee80211_mgd_deauth(IEEE80211_DEV_TO_SUB_IF(dev), + req, cookie); } static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_disassoc_request *req) + struct cfg80211_disassoc_request *req, + void *cookie) { - return ieee80211_mgd_disassoc(IEEE80211_DEV_TO_SUB_IF(dev), req); + return ieee80211_mgd_disassoc(IEEE80211_DEV_TO_SUB_IF(dev), + req, cookie); } static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 2e92bbd9b2d0..327aabc07abe 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -918,9 +918,11 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, struct cfg80211_assoc_request *req); int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, - struct cfg80211_deauth_request *req); + struct cfg80211_deauth_request *req, + void *cookie); int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, - struct cfg80211_disassoc_request *req); + struct cfg80211_disassoc_request *req, + void *cookie); ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); void ieee80211_send_pspoll(struct ieee80211_local *local, diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 15dbb57ab55e..c9db9646025b 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -386,7 +386,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, - const u8 *bssid, u16 stype, u16 reason) + const u8 *bssid, u16 stype, u16 reason, + void *cookie) { struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; @@ -412,9 +413,9 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, mgmt->u.deauth.reason_code = cpu_to_le16(reason); if (stype == IEEE80211_STYPE_DEAUTH) - cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, skb->len); + cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len, cookie); else - cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, skb->len); + cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len, cookie); ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED); } @@ -1837,10 +1838,12 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, /* no action */ break; case RX_MGMT_CFG80211_DEAUTH: - cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); + cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len, + NULL); break; case RX_MGMT_CFG80211_DISASSOC: - cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len); + cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len, + NULL); break; default: WARN(1, "unexpected: %d", rma); @@ -2273,7 +2276,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, } int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, - struct cfg80211_deauth_request *req) + struct cfg80211_deauth_request *req, + void *cookie) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_mgd_work *wk; @@ -2305,13 +2309,15 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, mutex_unlock(&ifmgd->mtx); ieee80211_send_deauth_disassoc(sdata, bssid, - IEEE80211_STYPE_DEAUTH, req->reason_code); + IEEE80211_STYPE_DEAUTH, req->reason_code, + cookie); return 0; } int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, - struct cfg80211_disassoc_request *req) + struct cfg80211_disassoc_request *req, + void *cookie) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; @@ -2331,6 +2337,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, mutex_unlock(&ifmgd->mtx); ieee80211_send_deauth_disassoc(sdata, req->bss->bssid, - IEEE80211_STYPE_DISASSOC, req->reason_code); + IEEE80211_STYPE_DISASSOC, req->reason_code, + cookie); return 0; } -- cgit v1.2.3 From 99783e2cde6eccbd31efeb03a79f26bb5f239c36 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jul 2009 03:54:43 +0200 Subject: mac80211: fix sparse warning ieee80211_testmode_cmd can very well be static. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 36f8f245fa4c..52928ad90570 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1293,7 +1293,7 @@ static void ieee80211_rfkill_poll(struct wiphy *wiphy) } #ifdef CONFIG_NL80211_TESTMODE -int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len) +static int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len) { struct ieee80211_local *local = wiphy_priv(wiphy); -- cgit v1.2.3 From 0a2b8bb24d4eb67788edd71d1ef8aa86c2e17e0f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Jul 2009 13:46:22 +0200 Subject: mac80211: driver operation debugging This makes mac80211 use the event tracing framework to log all operations as given to the driver. This will need to be extended with more information, but as a start it should be good. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/Kconfig | 12 + net/mac80211/Makefile | 3 + net/mac80211/driver-ops.h | 85 ++++-- net/mac80211/driver-trace.c | 6 + net/mac80211/driver-trace.h | 648 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 732 insertions(+), 22 deletions(-) create mode 100644 net/mac80211/driver-trace.c create mode 100644 net/mac80211/driver-trace.h (limited to 'net/mac80211') diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 182c9c5c6818..19a4c66e143e 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -206,3 +206,15 @@ config MAC80211_DEBUG_COUNTERS and show them in debugfs. If unsure, say N. + +config MAC80211_DRIVER_API_TRACER + bool "Driver API tracer" + depends on MAC80211_DEBUG_MENU + depends on EVENT_TRACING + help + Say Y here to make mac80211 register with the ftrace + framework for the driver API -- you can see which + driver methods it is calling then by looking at the + trace. + + If unsure, say N. diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 0e3ab88bb706..91284a74ff91 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -41,6 +41,9 @@ mac80211-$(CONFIG_MAC80211_MESH) += \ mac80211-$(CONFIG_PM) += pm.o +mac80211-$(CONFIG_MAC80211_DRIVER_API_TRACER) += driver-trace.o +CFLAGS_driver-trace.o := -I$(src) + # objects for PID algorithm rc80211_pid-y := rc80211_pid_algo.o rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index b13446afd48f..4100c361a99d 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -3,6 +3,7 @@ #include #include "ieee80211_i.h" +#include "driver-trace.h" static inline int drv_tx(struct ieee80211_local *local, struct sk_buff *skb) { @@ -11,29 +12,37 @@ static inline int drv_tx(struct ieee80211_local *local, struct sk_buff *skb) static inline int drv_start(struct ieee80211_local *local) { - return local->ops->start(&local->hw); + int ret = local->ops->start(&local->hw); + trace_drv_start(local, ret); + return ret; } static inline void drv_stop(struct ieee80211_local *local) { local->ops->stop(&local->hw); + trace_drv_stop(local); } static inline int drv_add_interface(struct ieee80211_local *local, struct ieee80211_if_init_conf *conf) { - return local->ops->add_interface(&local->hw, conf); + int ret = local->ops->add_interface(&local->hw, conf); + trace_drv_add_interface(local, conf->mac_addr, conf->vif, ret); + return ret; } static inline void drv_remove_interface(struct ieee80211_local *local, struct ieee80211_if_init_conf *conf) { local->ops->remove_interface(&local->hw, conf); + trace_drv_remove_interface(local, conf->mac_addr, conf->vif); } static inline int drv_config(struct ieee80211_local *local, u32 changed) { - return local->ops->config(&local->hw, changed); + int ret = local->ops->config(&local->hw, changed); + trace_drv_config(local, changed, ret); + return ret; } static inline void drv_bss_info_changed(struct ieee80211_local *local, @@ -43,6 +52,7 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local, { if (local->ops->bss_info_changed) local->ops->bss_info_changed(&local->hw, vif, info, changed); + trace_drv_bss_info_changed(local, vif, info, changed); } static inline void drv_configure_filter(struct ieee80211_local *local, @@ -53,14 +63,18 @@ static inline void drv_configure_filter(struct ieee80211_local *local, { local->ops->configure_filter(&local->hw, changed_flags, total_flags, mc_count, mc_list); + trace_drv_configure_filter(local, changed_flags, total_flags, + mc_count); } static inline int drv_set_tim(struct ieee80211_local *local, struct ieee80211_sta *sta, bool set) { + int ret = 0; if (local->ops->set_tim) - return local->ops->set_tim(&local->hw, sta, set); - return 0; + ret = local->ops->set_tim(&local->hw, sta, set); + trace_drv_set_tim(local, sta, set, ret); + return ret; } static inline int drv_set_key(struct ieee80211_local *local, @@ -68,7 +82,9 @@ static inline int drv_set_key(struct ieee80211_local *local, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { - return local->ops->set_key(&local->hw, cmd, vif, sta, key); + int ret = local->ops->set_key(&local->hw, cmd, vif, sta, key); + trace_drv_set_key(local, cmd, vif, sta, key, ret); + return ret; } static inline void drv_update_tkip_key(struct ieee80211_local *local, @@ -79,32 +95,41 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local, if (local->ops->update_tkip_key) local->ops->update_tkip_key(&local->hw, conf, address, iv32, phase1key); + trace_drv_update_tkip_key(local, conf, address, iv32); } static inline int drv_hw_scan(struct ieee80211_local *local, struct cfg80211_scan_request *req) { - return local->ops->hw_scan(&local->hw, req); + int ret = local->ops->hw_scan(&local->hw, req); + trace_drv_hw_scan(local, req, ret); + return ret; } static inline void drv_sw_scan_start(struct ieee80211_local *local) { if (local->ops->sw_scan_start) local->ops->sw_scan_start(&local->hw); + trace_drv_sw_scan_start(local); } static inline void drv_sw_scan_complete(struct ieee80211_local *local) { if (local->ops->sw_scan_complete) local->ops->sw_scan_complete(&local->hw); + trace_drv_sw_scan_complete(local); } static inline int drv_get_stats(struct ieee80211_local *local, struct ieee80211_low_level_stats *stats) { - if (!local->ops->get_stats) - return -EOPNOTSUPP; - return local->ops->get_stats(&local->hw, stats); + int ret = -EOPNOTSUPP; + + if (local->ops->get_stats) + ret = local->ops->get_stats(&local->hw, stats); + trace_drv_get_stats(local, stats, ret); + + return ret; } static inline void drv_get_tkip_seq(struct ieee80211_local *local, @@ -112,14 +137,17 @@ static inline void drv_get_tkip_seq(struct ieee80211_local *local, { if (local->ops->get_tkip_seq) local->ops->get_tkip_seq(&local->hw, hw_key_idx, iv32, iv16); + trace_drv_get_tkip_seq(local, hw_key_idx, iv32, iv16); } static inline int drv_set_rts_threshold(struct ieee80211_local *local, u32 value) { + int ret = 0; if (local->ops->set_rts_threshold) - return local->ops->set_rts_threshold(&local->hw, value); - return 0; + ret = local->ops->set_rts_threshold(&local->hw, value); + trace_drv_set_rts_threshold(local, value, ret); + return ret; } static inline void drv_sta_notify(struct ieee80211_local *local, @@ -129,46 +157,57 @@ static inline void drv_sta_notify(struct ieee80211_local *local, { if (local->ops->sta_notify) local->ops->sta_notify(&local->hw, vif, cmd, sta); + trace_drv_sta_notify(local, vif, cmd, sta); } static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue, const struct ieee80211_tx_queue_params *params) { + int ret = -EOPNOTSUPP; if (local->ops->conf_tx) - return local->ops->conf_tx(&local->hw, queue, params); - return -EOPNOTSUPP; + ret = local->ops->conf_tx(&local->hw, queue, params); + trace_drv_conf_tx(local, queue, params, ret); + return ret; } static inline int drv_get_tx_stats(struct ieee80211_local *local, struct ieee80211_tx_queue_stats *stats) { - return local->ops->get_tx_stats(&local->hw, stats); + int ret = local->ops->get_tx_stats(&local->hw, stats); + trace_drv_get_tx_stats(local, stats, ret); + return ret; } static inline u64 drv_get_tsf(struct ieee80211_local *local) { + u64 ret = -1ULL; if (local->ops->get_tsf) - return local->ops->get_tsf(&local->hw); - return -1ULL; + ret = local->ops->get_tsf(&local->hw); + trace_drv_get_tsf(local, ret); + return ret; } static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf) { if (local->ops->set_tsf) local->ops->set_tsf(&local->hw, tsf); + trace_drv_set_tsf(local, tsf); } static inline void drv_reset_tsf(struct ieee80211_local *local) { if (local->ops->reset_tsf) local->ops->reset_tsf(&local->hw); + trace_drv_reset_tsf(local); } static inline int drv_tx_last_beacon(struct ieee80211_local *local) { + int ret = 1; if (local->ops->tx_last_beacon) - return local->ops->tx_last_beacon(&local->hw); - return 1; + ret = local->ops->tx_last_beacon(&local->hw); + trace_drv_tx_last_beacon(local, ret); + return ret; } static inline int drv_ampdu_action(struct ieee80211_local *local, @@ -176,10 +215,12 @@ static inline int drv_ampdu_action(struct ieee80211_local *local, struct ieee80211_sta *sta, u16 tid, u16 *ssn) { + int ret = -EOPNOTSUPP; if (local->ops->ampdu_action) - return local->ops->ampdu_action(&local->hw, action, - sta, tid, ssn); - return -EOPNOTSUPP; + ret = local->ops->ampdu_action(&local->hw, action, + sta, tid, ssn); + trace_drv_ampdu_action(local, action, sta, tid, ssn, ret); + return ret; } diff --git a/net/mac80211/driver-trace.c b/net/mac80211/driver-trace.c new file mode 100644 index 000000000000..6da6f79932fc --- /dev/null +++ b/net/mac80211/driver-trace.c @@ -0,0 +1,6 @@ +/* bug in tracepoint.h, it should include this */ +#include + +#include "driver-ops.h" +#define CREATE_TRACE_POINTS +#include "driver-trace.h" diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h new file mode 100644 index 000000000000..48c93d13e7b0 --- /dev/null +++ b/net/mac80211/driver-trace.h @@ -0,0 +1,648 @@ +#if !defined(__MAC80211_DRIVER_TRACE) || defined(TRACE_HEADER_MULTI_READ) +#define __MAC80211_DRIVER_TRACE + +#include +#include +#include "ieee80211_i.h" + +#ifndef CONFIG_MAC80211_DRIVER_API_TRACER +#undef TRACE_EVENT +#define TRACE_EVENT(name, proto, ...) \ +static inline void trace_ ## name(proto) {} +#endif + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM mac80211 + +#define MAXNAME 32 +#define LOCAL_ENTRY __array(char, wiphy_name, 32) +#define LOCAL_ASSIGN strlcpy(__entry->wiphy_name, wiphy_name(local->hw.wiphy), MAXNAME) +#define LOCAL_PR_FMT "%s" +#define LOCAL_PR_ARG __entry->wiphy_name + +#define STA_ENTRY __array(char, sta_addr, ETH_ALEN) +#define STA_ASSIGN (sta ? memcpy(__entry->sta_addr, sta->addr, ETH_ALEN) : memset(__entry->sta_addr, 0, ETH_ALEN)) +#define STA_PR_FMT " sta:%pM" +#define STA_PR_ARG __entry->sta_addr + +#define VIF_ENTRY __field(enum nl80211_iftype, vif_type) __field(void *, vif) +#define VIF_ASSIGN __entry->vif_type = vif ? vif->type : 0; __entry->vif = vif +#define VIF_PR_FMT " vif:%p(%d)" +#define VIF_PR_ARG __entry->vif, __entry->vif_type + +TRACE_EVENT(drv_start, + TP_PROTO(struct ieee80211_local *local, int ret), + + TP_ARGS(local, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(int, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->ret = ret; + ), + + TP_printk( + LOCAL_PR_FMT, LOCAL_PR_ARG + ) +); + +TRACE_EVENT(drv_stop, + TP_PROTO(struct ieee80211_local *local), + + TP_ARGS(local), + + TP_STRUCT__entry( + LOCAL_ENTRY + ), + + TP_fast_assign( + LOCAL_ASSIGN; + ), + + TP_printk( + LOCAL_PR_FMT, LOCAL_PR_ARG + ) +); + +TRACE_EVENT(drv_add_interface, + TP_PROTO(struct ieee80211_local *local, + const u8 *addr, + struct ieee80211_vif *vif, + int ret), + + TP_ARGS(local, addr, vif, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + __array(char, addr, 6) + __field(int, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + memcpy(__entry->addr, addr, 6); + __entry->ret = ret; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT " addr:%pM ret:%d", + LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr, __entry->ret + ) +); + +TRACE_EVENT(drv_remove_interface, + TP_PROTO(struct ieee80211_local *local, + const u8 *addr, struct ieee80211_vif *vif), + + TP_ARGS(local, addr, vif), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + __array(char, addr, 6) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + memcpy(__entry->addr, addr, 6); + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT " addr:%pM", + LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr + ) +); + +TRACE_EVENT(drv_config, + TP_PROTO(struct ieee80211_local *local, + u32 changed, + int ret), + + TP_ARGS(local, changed, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(u32, changed) + __field(int, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->changed = changed; + __entry->ret = ret; + ), + + TP_printk( + LOCAL_PR_FMT " ch:%#x ret:%d", + LOCAL_PR_ARG, __entry->changed, __entry->ret + ) +); + +TRACE_EVENT(drv_bss_info_changed, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed), + + TP_ARGS(local, vif, info, changed), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + __field(bool, assoc) + __field(u16, aid) + __field(bool, cts) + __field(bool, shortpre) + __field(bool, shortslot) + __field(u8, dtimper) + __field(u16, bcnint) + __field(u16, assoc_cap) + __field(u64, timestamp) + __field(u32, basic_rates) + __field(u32, changed) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + __entry->changed = changed; + __entry->aid = info->aid; + __entry->assoc = info->assoc; + __entry->shortpre = info->use_short_preamble; + __entry->cts = info->use_cts_prot; + __entry->shortslot = info->use_short_slot; + __entry->dtimper = info->dtim_period; + __entry->bcnint = info->beacon_int; + __entry->assoc_cap = info->assoc_capability; + __entry->timestamp = info->timestamp; + __entry->basic_rates = info->basic_rates; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT " changed:%#x", + LOCAL_PR_ARG, VIF_PR_ARG, __entry->changed + ) +); + +TRACE_EVENT(drv_configure_filter, + TP_PROTO(struct ieee80211_local *local, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count), + + TP_ARGS(local, changed_flags, total_flags, mc_count), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(unsigned int, changed) + __field(unsigned int, total) + __field(int, mc) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->changed = changed_flags; + __entry->total = *total_flags; + __entry->mc = mc_count; + ), + + TP_printk( + LOCAL_PR_FMT " changed:%#x total:%#x mc:%d", + LOCAL_PR_ARG, __entry->changed, __entry->total, __entry->mc + ) +); + +TRACE_EVENT(drv_set_tim, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sta *sta, bool set, int ret), + + TP_ARGS(local, sta, set, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + STA_ENTRY + __field(bool, set) + __field(int, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + STA_ASSIGN; + __entry->set = set; + __entry->ret = ret; + ), + + TP_printk( + LOCAL_PR_FMT STA_PR_FMT " set:%d ret:%d", + LOCAL_PR_ARG, STA_PR_FMT, __entry->set, __entry->ret + ) +); + +TRACE_EVENT(drv_set_key, + TP_PROTO(struct ieee80211_local *local, + enum set_key_cmd cmd, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, int ret), + + TP_ARGS(local, cmd, vif, sta, key, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + STA_ENTRY + __field(enum ieee80211_key_alg, alg) + __field(u8, hw_key_idx) + __field(u8, flags) + __field(s8, keyidx) + __field(int, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + STA_ASSIGN; + __entry->alg = key->alg; + __entry->flags = key->flags; + __entry->keyidx = key->keyidx; + __entry->hw_key_idx = key->hw_key_idx; + __entry->ret = ret; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " ret:%d", + LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->ret + ) +); + +TRACE_EVENT(drv_update_tkip_key, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_key_conf *conf, + const u8 *address, u32 iv32), + + TP_ARGS(local, conf, address, iv32), + + TP_STRUCT__entry( + LOCAL_ENTRY + __array(u8, addr, 6) + __field(u32, iv32) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + memcpy(__entry->addr, address, 6); + __entry->iv32 = iv32; + ), + + TP_printk( + LOCAL_PR_FMT " addr:%pM iv32:%#x", + LOCAL_PR_ARG, __entry->addr, __entry->iv32 + ) +); + +TRACE_EVENT(drv_hw_scan, + TP_PROTO(struct ieee80211_local *local, + struct cfg80211_scan_request *req, int ret), + + TP_ARGS(local, req, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(int, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->ret = ret; + ), + + TP_printk( + LOCAL_PR_FMT " ret:%d", + LOCAL_PR_ARG, __entry->ret + ) +); + +TRACE_EVENT(drv_sw_scan_start, + TP_PROTO(struct ieee80211_local *local), + + TP_ARGS(local), + + TP_STRUCT__entry( + LOCAL_ENTRY + ), + + TP_fast_assign( + LOCAL_ASSIGN; + ), + + TP_printk( + LOCAL_PR_FMT, LOCAL_PR_ARG + ) +); + +TRACE_EVENT(drv_sw_scan_complete, + TP_PROTO(struct ieee80211_local *local), + + TP_ARGS(local), + + TP_STRUCT__entry( + LOCAL_ENTRY + ), + + TP_fast_assign( + LOCAL_ASSIGN; + ), + + TP_printk( + LOCAL_PR_FMT, LOCAL_PR_ARG + ) +); + +TRACE_EVENT(drv_get_stats, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_low_level_stats *stats, + int ret), + + TP_ARGS(local, stats, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(int, ret) + __field(unsigned int, ackfail) + __field(unsigned int, rtsfail) + __field(unsigned int, fcserr) + __field(unsigned int, rtssucc) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->ret = ret; + __entry->ackfail = stats->dot11ACKFailureCount; + __entry->rtsfail = stats->dot11RTSFailureCount; + __entry->fcserr = stats->dot11FCSErrorCount; + __entry->rtssucc = stats->dot11RTSSuccessCount; + ), + + TP_printk( + LOCAL_PR_FMT " ret:%d", + LOCAL_PR_ARG, __entry->ret + ) +); + +TRACE_EVENT(drv_get_tkip_seq, + TP_PROTO(struct ieee80211_local *local, + u8 hw_key_idx, u32 *iv32, u16 *iv16), + + TP_ARGS(local, hw_key_idx, iv32, iv16), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(u8, hw_key_idx) + __field(u32, iv32) + __field(u16, iv16) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->hw_key_idx = hw_key_idx; + __entry->iv32 = *iv32; + __entry->iv16 = *iv16; + ), + + TP_printk( + LOCAL_PR_FMT, LOCAL_PR_ARG + ) +); + +TRACE_EVENT(drv_set_rts_threshold, + TP_PROTO(struct ieee80211_local *local, u32 value, int ret), + + TP_ARGS(local, value, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(u32, value) + __field(int, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->ret = ret; + __entry->value = value; + ), + + TP_printk( + LOCAL_PR_FMT " value:%d ret:%d", + LOCAL_PR_ARG, __entry->value, __entry->ret + ) +); + +TRACE_EVENT(drv_sta_notify, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, + struct ieee80211_sta *sta), + + TP_ARGS(local, vif, cmd, sta), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + STA_ENTRY + __field(u32, cmd) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + STA_ASSIGN; + __entry->cmd = cmd; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " cmd:%d", + LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->cmd + ) +); + +TRACE_EVENT(drv_conf_tx, + TP_PROTO(struct ieee80211_local *local, u16 queue, + const struct ieee80211_tx_queue_params *params, + int ret), + + TP_ARGS(local, queue, params, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(u16, queue) + __field(u16, txop) + __field(u16, cw_min) + __field(u16, cw_max) + __field(u8, aifs) + __field(int, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->queue = queue; + __entry->ret = ret; + __entry->txop = params->txop; + __entry->cw_max = params->cw_max; + __entry->cw_min = params->cw_min; + __entry->aifs = params->aifs; + ), + + TP_printk( + LOCAL_PR_FMT " queue:%d ret:%d", + LOCAL_PR_ARG, __entry->queue, __entry->ret + ) +); + +TRACE_EVENT(drv_get_tx_stats, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_tx_queue_stats *stats, + int ret), + + TP_ARGS(local, stats, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(int, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->ret = ret; + ), + + TP_printk( + LOCAL_PR_FMT " ret:%d", + LOCAL_PR_ARG, __entry->ret + ) +); + +TRACE_EVENT(drv_get_tsf, + TP_PROTO(struct ieee80211_local *local, u64 ret), + + TP_ARGS(local, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(u64, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->ret = ret; + ), + + TP_printk( + LOCAL_PR_FMT " ret:%llu", + LOCAL_PR_ARG, (unsigned long long)__entry->ret + ) +); + +TRACE_EVENT(drv_set_tsf, + TP_PROTO(struct ieee80211_local *local, u64 tsf), + + TP_ARGS(local, tsf), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(u64, tsf) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->tsf = tsf; + ), + + TP_printk( + LOCAL_PR_FMT " tsf:%llu", + LOCAL_PR_ARG, (unsigned long long)__entry->tsf + ) +); + +TRACE_EVENT(drv_reset_tsf, + TP_PROTO(struct ieee80211_local *local), + + TP_ARGS(local), + + TP_STRUCT__entry( + LOCAL_ENTRY + ), + + TP_fast_assign( + LOCAL_ASSIGN; + ), + + TP_printk( + LOCAL_PR_FMT, LOCAL_PR_ARG + ) +); + +TRACE_EVENT(drv_tx_last_beacon, + TP_PROTO(struct ieee80211_local *local, int ret), + + TP_ARGS(local, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(int, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->ret = ret; + ), + + TP_printk( + LOCAL_PR_FMT " ret:%d", + LOCAL_PR_ARG, __entry->ret + ) +); + +TRACE_EVENT(drv_ampdu_action, + TP_PROTO(struct ieee80211_local *local, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, u16 tid, + u16 *ssn, int ret), + + TP_ARGS(local, action, sta, tid, ssn, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + STA_ENTRY + __field(u32, action) + __field(u16, tid) + __field(u16, ssn) + __field(int, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + STA_ASSIGN; + __entry->ret = ret; + __entry->action = action; + __entry->tid = tid; + __entry->ssn = *ssn; + ), + + TP_printk( + LOCAL_PR_FMT STA_PR_FMT " action:%d tid:%d ret:%d", + LOCAL_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret + ) +); +#endif /* __MAC80211_DRIVER_TRACE */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE driver-trace +#include -- cgit v1.2.3 From 10c836d7896e9d7b683a76f3cac3c289d8da72ef Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Thu, 9 Jul 2009 14:42:16 -0700 Subject: mac80211: Assign next hop address to pending mesh frames Assign next hop address to pending mesh frames once the path is resolved. Regression. Frames transmitted when a mesh path was wating to be resolved were being transmitted with an invalid Receiver Address. [Changes since v1] Suggested by Johannes: - Improved frame_queue traversal - Narower RCU scope Signed-off-by: Javier Cardona Signed-off-by: Andrey Yurovsky Signed-off-by: John W. Linville --- net/mac80211/mesh_pathtbl.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'net/mac80211') diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 479597e88583..f0304bfdcdff 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -55,7 +55,25 @@ static DEFINE_RWLOCK(pathtbl_resize_lock); */ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta) { + struct sk_buff *skb; + struct ieee80211_hdr *hdr; + struct sk_buff_head tmpq; + unsigned long flags; + rcu_assign_pointer(mpath->next_hop, sta); + + __skb_queue_head_init(&tmpq); + + spin_lock_irqsave(&mpath->frame_queue.lock, flags); + + while ((skb = __skb_dequeue(&mpath->frame_queue)) != NULL) { + hdr = (struct ieee80211_hdr *) skb->data; + memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN); + __skb_queue_tail(&tmpq, skb); + } + + skb_queue_splice(&tmpq, &mpath->frame_queue); + spin_unlock_irqrestore(&mpath->frame_queue.lock, flags); } -- cgit v1.2.3 From fffd0934b9390f34bec45762192b7edd3b12b4b5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 8 Jul 2009 14:22:54 +0200 Subject: cfg80211: rework key operation This reworks the key operation in cfg80211, and now only allows, from userspace, configuring keys (via nl80211) after the connection has been established (in managed mode), the IBSS been joined (in IBSS mode), at any time (in AP[_VLAN] modes) or never for all the other modes. In order to do shared key authentication correctly, it is now possible to give a WEP key to the AUTH command. To configure static WEP keys, these are given to the CONNECT or IBSS_JOIN command directly, for a userspace SME it is assumed it will configure it properly after the connection has been established. Since mac80211 used to check the default key in IBSS mode to see whether or not the network is protected, it needs an update in that area, as well as an update to make use of the WEP key passed to auth() for shared key authentication. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ibss.c | 9 +++++---- net/mac80211/ieee80211_i.h | 8 ++++++-- net/mac80211/mlme.c | 11 +++++++++-- net/mac80211/util.c | 16 +++++++++++----- net/mac80211/wep.c | 6 +++--- net/mac80211/wep.h | 3 +++ 6 files changed, 37 insertions(+), 16 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 15d5a53b59a8..8e2220000e5c 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -57,7 +57,7 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, */ if (auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1) ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, NULL, 0, - sdata->u.ibss.bssid, 0); + sdata->u.ibss.bssid, NULL, 0, 0); } static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, @@ -494,7 +494,7 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) capability = WLAN_CAPABILITY_IBSS; - if (sdata->default_key) + if (ifibss->privacy) capability |= WLAN_CAPABILITY_PRIVACY; else sdata->drop_unencrypted = 0; @@ -524,9 +524,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) return; capability = WLAN_CAPABILITY_IBSS; - if (sdata->default_key) + if (ifibss->privacy) capability |= WLAN_CAPABILITY_PRIVACY; - if (ifibss->fixed_bssid) bssid = ifibss->bssid; if (ifibss->fixed_channel) @@ -872,6 +871,8 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, } else sdata->u.ibss.fixed_bssid = false; + sdata->u.ibss.privacy = params->privacy; + sdata->vif.bss_conf.beacon_int = params->beacon_interval; sdata->u.ibss.channel = params->channel; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 327aabc07abe..06b3411530f2 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -247,6 +247,9 @@ struct ieee80211_mgd_work { int tries; + u8 key[WLAN_KEY_LEN_WEP104]; + u8 key_len, key_idx; + /* must be last */ u8 ie[0]; /* for auth or assoc frame, not probe */ }; @@ -321,6 +324,7 @@ struct ieee80211_if_ibss { bool fixed_bssid; bool fixed_channel; + bool privacy; u8 bssid[ETH_ALEN]; u8 ssid[IEEE80211_MAX_SSID_LEN]; @@ -1093,8 +1097,8 @@ int ieee80211_add_pending_skbs(struct ieee80211_local *local, void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, u16 transaction, u16 auth_alg, - u8 *extra, size_t extra_len, - const u8 *bssid, int encrypt); + u8 *extra, size_t extra_len, const u8 *bssid, + const u8 *key, u8 key_len, u8 key_idx); int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, const u8 *ie, size_t ie_len); void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c9db9646025b..8e4a60497bba 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -954,7 +954,7 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, sdata->dev->name, wk->bss->cbss.bssid, wk->tries); ieee80211_send_auth(sdata, 1, wk->auth_alg, wk->ie, wk->ie_len, - wk->bss->cbss.bssid, 0); + wk->bss->cbss.bssid, NULL, 0, 0); wk->auth_transaction = 2; wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; @@ -1176,7 +1176,8 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, return; ieee80211_send_auth(sdata, 3, wk->auth_alg, elems.challenge - 2, elems.challenge_len + 2, - wk->bss->cbss.bssid, 1); + wk->bss->cbss.bssid, + wk->key, wk->key_len, wk->key_idx); wk->auth_transaction = 4; } @@ -2175,6 +2176,12 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, wk->ie_len = req->ie_len; } + if (req->key && req->key_len) { + wk->key_len = req->key_len; + wk->key_idx = req->key_idx; + memcpy(wk->key, req->key, req->key_len); + } + ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); memcpy(wk->ssid, ssid + 2, ssid[1]); wk->ssid_len = ssid[1]; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 915e77769312..dbf66b52d38c 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -31,6 +31,7 @@ #include "mesh.h" #include "wme.h" #include "led.h" +#include "wep.h" /* privid for wiphys to determine whether they belong to us or not */ void *mac80211_wiphy_privid = &mac80211_wiphy_privid; @@ -804,12 +805,13 @@ u32 ieee80211_mandatory_rates(struct ieee80211_local *local, void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, u16 transaction, u16 auth_alg, - u8 *extra, size_t extra_len, - const u8 *bssid, int encrypt) + u8 *extra, size_t extra_len, const u8 *bssid, + const u8 *key, u8 key_len, u8 key_idx) { struct ieee80211_local *local = sdata->local; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; + int err; skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 6 + extra_len); @@ -824,8 +826,6 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, memset(mgmt, 0, 24 + 6); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH); - if (encrypt) - mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); memcpy(mgmt->da, bssid, ETH_ALEN); memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); memcpy(mgmt->bssid, bssid, ETH_ALEN); @@ -835,7 +835,13 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, if (extra) memcpy(skb_put(skb, extra_len), extra, extra_len); - ieee80211_tx_skb(sdata, skb, encrypt); + if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) { + mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); + err = ieee80211_wep_encrypt(local, skb, key, key_len, key_idx); + WARN_ON(err); + } + + ieee80211_tx_skb(sdata, skb, 0); } int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 4fafb2d27c84..8a980f136941 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -144,9 +144,9 @@ void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, * * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data)) */ -static int ieee80211_wep_encrypt(struct ieee80211_local *local, - struct sk_buff *skb, - const u8 *key, int keylen, int keyidx) +int ieee80211_wep_encrypt(struct ieee80211_local *local, + struct sk_buff *skb, + const u8 *key, int keylen, int keyidx) { u8 *iv; size_t len; diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h index 85219ded8703..fe29d7e5759f 100644 --- a/net/mac80211/wep.h +++ b/net/mac80211/wep.h @@ -20,6 +20,9 @@ int ieee80211_wep_init(struct ieee80211_local *local); void ieee80211_wep_free(struct ieee80211_local *local); void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, size_t klen, u8 *data, size_t data_len); +int ieee80211_wep_encrypt(struct ieee80211_local *local, + struct sk_buff *skb, + const u8 *key, int keylen, int keyidx); int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, size_t klen, u8 *data, size_t data_len); bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key); -- cgit v1.2.3 From ca386f3137eb68621fadba546d9eb35ac2f82de3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Jul 2009 02:39:48 +0200 Subject: mac80211: fix multi-use timer We have, sometimes, multiple things that want to run but don't have their own timer. Introduce a new function to mac80211's mlme run_again() that makes sure that the timer will run again at the _first_ needed time, use that function and also properly reprogram the timer once it fired. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 8e4a60497bba..c1114bb8095b 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -72,6 +72,26 @@ static inline void ASSERT_MGD_MTX(struct ieee80211_if_managed *ifmgd) WARN_ON(!mutex_is_locked(&ifmgd->mtx)); } +/* + * We can have multiple work items (and connection probing) + * scheduling this timer, but we need to take care to only + * reschedule it when it should fire _earlier_ than it was + * asked for before, or if it's not pending right now. This + * function ensures that. Note that it then is required to + * run this function for all timeouts after the first one + * has happened -- the work that runs from this timer will + * do that. + */ +static void run_again(struct ieee80211_if_managed *ifmgd, + unsigned long timeout) +{ + ASSERT_MGD_MTX(ifmgd); + + if (!timer_pending(&ifmgd->timer) || + time_before(timeout, ifmgd->timer.expires)) + mod_timer(&ifmgd->timer, timeout); +} + static int ecw2cw(int ecw) { return (1 << ecw) - 1; @@ -916,7 +936,7 @@ ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, ieee80211_send_probe_req(sdata, NULL, wk->ssid, wk->ssid_len, NULL, 0); wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; - mod_timer(&ifmgd->timer, wk->timeout); + run_again(ifmgd, wk->timeout); return RX_MGMT_NONE; } @@ -958,7 +978,7 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, wk->auth_transaction = 2; wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; - mod_timer(&ifmgd->timer, wk->timeout); + run_again(ifmgd, wk->timeout); return RX_MGMT_NONE; } @@ -1079,7 +1099,7 @@ ieee80211_associate(struct ieee80211_sub_if_data *sdata, ieee80211_send_assoc(sdata, wk); wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; - mod_timer(&ifmgd->timer, wk->timeout); + run_again(ifmgd, wk->timeout); return RX_MGMT_NONE; } @@ -1140,7 +1160,7 @@ void ieee80211_beacon_loss_work(struct work_struct *work) ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid, ssid + 2, ssid[1], NULL, 0); - mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT); + run_again(ifmgd, jiffies + IEEE80211_PROBE_WAIT); out: mutex_unlock(&ifmgd->mtx); } @@ -1350,8 +1370,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, sdata->dev->name, tu, ms); wk->timeout = jiffies + msecs_to_jiffies(ms); if (ms > IEEE80211_ASSOC_TIMEOUT) - mod_timer(&ifmgd->timer, - jiffies + msecs_to_jiffies(ms)); + run_again(ifmgd, jiffies + msecs_to_jiffies(ms)); return RX_MGMT_NONE; } @@ -1981,8 +2000,15 @@ static void ieee80211_sta_work(struct work_struct *work) } list_for_each_entry_safe(wk, tmp, &ifmgd->work_list, list) { - if (time_before(jiffies, wk->timeout)) + if (time_is_after_jiffies(wk->timeout)) { + /* + * This work item isn't supposed to be worked on + * right now, but take care to adjust the timer + * properly. + */ + run_again(ifmgd, wk->timeout); continue; + } switch (wk->state) { default: -- cgit v1.2.3 From b291ba11181d46dfbd2d7a5c00a5f3335228191e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Jul 2009 15:29:03 +0200 Subject: mac80211: monitor the connection With the recent MLME rework I accidentally removed the connection monitoring code. In order to add it back, this patch will add new code to monitor both for beacon loss and for the connection actually working, with possibly separate triggers. When no unicast frames have been received from the AP for (currently) two seconds, we will send the AP a probe request. Also, when we don't see beacons from the AP for two seconds, we do the same (but those times need not be the same due to the way the code is now written). Additionally, clean up the parameters to the ieee80211_set_disassoc() function that I need here, those are all useless except sdata. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 20 ++-- net/mac80211/mlme.c | 257 ++++++++++++++++++++++++++++++++++++--------- net/mac80211/rx.c | 22 ++-- 3 files changed, 227 insertions(+), 72 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 06b3411530f2..a34bca2dc52f 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -256,12 +256,13 @@ struct ieee80211_mgd_work { /* flags used in struct ieee80211_if_managed.flags */ enum ieee80211_sta_flags { - IEEE80211_STA_PROBEREQ_POLL = BIT(3), - IEEE80211_STA_CONTROL_PORT = BIT(4), - IEEE80211_STA_WMM_ENABLED = BIT(5), - IEEE80211_STA_DISABLE_11N = BIT(6), - IEEE80211_STA_CSA_RECEIVED = BIT(7), - IEEE80211_STA_MFP_ENABLED = BIT(8), + IEEE80211_STA_BEACON_POLL = BIT(0), + IEEE80211_STA_CONNECTION_POLL = BIT(1), + IEEE80211_STA_CONTROL_PORT = BIT(2), + IEEE80211_STA_WMM_ENABLED = BIT(3), + IEEE80211_STA_DISABLE_11N = BIT(4), + IEEE80211_STA_CSA_RECEIVED = BIT(5), + IEEE80211_STA_MFP_ENABLED = BIT(6), }; /* flags for MLME request */ @@ -271,11 +272,16 @@ enum ieee80211_sta_request { struct ieee80211_if_managed { struct timer_list timer; + struct timer_list conn_mon_timer; + struct timer_list bcn_mon_timer; struct timer_list chswitch_timer; struct work_struct work; + struct work_struct monitor_work; struct work_struct chswitch_work; struct work_struct beacon_loss_work; + unsigned long probe_timeout; + struct mutex mtx; struct ieee80211_bss *associated; struct list_head work_list; @@ -292,8 +298,6 @@ struct ieee80211_if_managed { unsigned long request; - unsigned long last_beacon; - unsigned int flags; u32 beacon_crc; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c1114bb8095b..18dad229344c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -31,8 +31,23 @@ #define IEEE80211_AUTH_MAX_TRIES 3 #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) #define IEEE80211_ASSOC_MAX_TRIES 3 -#define IEEE80211_MONITORING_INTERVAL (2 * HZ) -#define IEEE80211_PROBE_WAIT (HZ / 5) + +/* + * beacon loss detection timeout + * XXX: should depend on beacon interval + */ +#define IEEE80211_BEACON_LOSS_TIME (2 * HZ) +/* + * Time the connection can be idle before we probe + * it to see if we can still talk to the AP. + */ +#define IEEE80211_CONNECTION_IDLE_TIME (2 * HZ) +/* + * Time we wait for a probe response after sending + * a probe request because of beacon loss or for + * checking the connection still works. + */ +#define IEEE80211_PROBE_WAIT (HZ / 5) #define TMR_RUNNING_TIMER 0 #define TMR_RUNNING_CHANSW 1 @@ -92,6 +107,15 @@ static void run_again(struct ieee80211_if_managed *ifmgd, mod_timer(&ifmgd->timer, timeout); } +static void mod_beacon_timer(struct ieee80211_sub_if_data *sdata) +{ + if (sdata->local->hw.flags & IEEE80211_HW_BEACON_FILTER) + return; + + mod_timer(&sdata->u.mgd.bcn_mon_timer, + round_jiffies_up(jiffies + IEEE80211_BEACON_LOSS_TIME)); +} + static int ecw2cw(int ecw) { return (1 << ecw) - 1; @@ -666,7 +690,8 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) if (count == 1 && found->u.mgd.powersave && found->u.mgd.associated && list_empty(&found->u.mgd.work_list) && - !(found->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL)) { + !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL | + IEEE80211_STA_CONNECTION_POLL))) { s32 beaconint_us; if (latency < 0) @@ -872,6 +897,10 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, sdata->u.mgd.associated = bss; memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN); + /* just to be sure */ + sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL | + IEEE80211_STA_BEACON_POLL); + ieee80211_led_assoc(local, 1); sdata->vif.bss_conf.assoc = 1; @@ -983,16 +1012,21 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, return RX_MGMT_NONE; } -static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, - const u8 *bssid, bool deauth) +static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; struct sta_info *sta; u32 changed = 0, config_changed = 0; + u8 bssid[ETH_ALEN]; ASSERT_MGD_MTX(ifmgd); + if (WARN_ON(!ifmgd->associated)) + return; + + memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN); + ifmgd->associated = NULL; memset(ifmgd->bssid, 0, ETH_ALEN); @@ -1112,32 +1146,22 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, * from AP because we know that the connection is working both ways * at that time. But multicast frames (and hence also beacons) must * be ignored here, because we need to trigger the timer during - * data idle periods for sending the periodical probe request to - * the AP. + * data idle periods for sending the periodic probe request to the + * AP we're connected to. */ - if (!is_multicast_ether_addr(hdr->addr1)) - mod_timer(&sdata->u.mgd.timer, - jiffies + IEEE80211_MONITORING_INTERVAL); + if (is_multicast_ether_addr(hdr->addr1)) + return; + + mod_timer(&sdata->u.mgd.conn_mon_timer, + round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME)); } -void ieee80211_beacon_loss_work(struct work_struct *work) +static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, + bool beacon) { - struct ieee80211_sub_if_data *sdata = - container_of(work, struct ieee80211_sub_if_data, - u.mgd.beacon_loss_work); struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; const u8 *ssid; - - /* - * The driver has already reported this event and we have - * already sent a probe request. Maybe the AP died and the - * driver keeps reporting until we disassociate... We have - * to ignore that because otherwise we would continually - * reset the timer and never check whether we received a - * probe response! - */ - if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) - return; + bool already = false; mutex_lock(&ifmgd->mtx); @@ -1145,12 +1169,35 @@ void ieee80211_beacon_loss_work(struct work_struct *work) goto out; #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - if (net_ratelimit()) - printk(KERN_DEBUG "%s: driver reports beacon loss from AP " + if (beacon && net_ratelimit()) + printk(KERN_DEBUG "%s: detected beacon loss from AP " "- sending probe request\n", sdata->dev->name); #endif - ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; + /* + * The driver/our work has already reported this event or the + * connection monitoring has kicked in and we have already sent + * a probe request. Or maybe the AP died and the driver keeps + * reporting until we disassociate... + * + * In either case we have to ignore the current call to this + * function (except for setting the correct probe reason bit) + * because otherwise we would reset the timer every time and + * never check whether we received a probe response! + */ + if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | + IEEE80211_STA_CONNECTION_POLL)) + already = true; + + if (beacon) + ifmgd->flags |= IEEE80211_STA_BEACON_POLL; + else + ifmgd->flags |= IEEE80211_STA_CONNECTION_POLL; + + if (already) + goto out; + + ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT; mutex_lock(&sdata->local->iflist_mtx); ieee80211_recalc_ps(sdata->local, -1); @@ -1160,11 +1207,21 @@ void ieee80211_beacon_loss_work(struct work_struct *work) ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid, ssid + 2, ssid[1], NULL, 0); - run_again(ifmgd, jiffies + IEEE80211_PROBE_WAIT); + run_again(ifmgd, ifmgd->probe_timeout); + out: mutex_unlock(&ifmgd->mtx); } +void ieee80211_beacon_loss_work(struct work_struct *work) +{ + struct ieee80211_sub_if_data *sdata = + container_of(work, struct ieee80211_sub_if_data, + u.mgd.beacon_loss_work); + + ieee80211_mgd_probe_ap(sdata, true); +} + void ieee80211_beacon_loss(struct ieee80211_vif *vif) { struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); @@ -1278,7 +1335,7 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, sdata->dev->name, bssid, reason_code); if (!wk) { - ieee80211_set_disassoc(sdata, bssid, true); + ieee80211_set_disassoc(sdata); } else { list_del(&wk->list); kfree(wk); @@ -1311,7 +1368,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", sdata->dev->name, reason_code); - ieee80211_set_disassoc(sdata, ifmgd->associated->cbss.bssid, false); + ieee80211_set_disassoc(sdata); return RX_MGMT_CFG80211_DISASSOC; } @@ -1412,9 +1469,6 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, return RX_MGMT_NONE; } - /* update new sta with its last rx activity */ - sta->last_rx = jiffies; - set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP); if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) @@ -1517,10 +1571,11 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, ieee80211_set_associated(sdata, wk->bss, changed); /* - * initialise the time of last beacon to be the association time, - * otherwise beacon loss check will trigger immediately + * Start timer to probe the connection to the AP now. + * Also start the timer that will detect beacon loss. */ - ifmgd->last_beacon = jiffies; + ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); + mod_beacon_timer(sdata); list_del(&wk->list); kfree(wk); @@ -1604,11 +1659,22 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, if (ifmgd->associated && memcmp(mgmt->bssid, ifmgd->associated->cbss.bssid, ETH_ALEN) == 0 && - ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) { - ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; + ifmgd->flags & (IEEE80211_STA_BEACON_POLL | + IEEE80211_STA_CONNECTION_POLL)) { + ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | + IEEE80211_STA_BEACON_POLL); mutex_lock(&sdata->local->iflist_mtx); ieee80211_recalc_ps(sdata->local, -1); mutex_unlock(&sdata->local->iflist_mtx); + /* + * We've received a probe response, but are not sure whether + * we have or will be receiving any beacons or data, so let's + * schedule the timers again, just in case. + */ + mod_beacon_timer(sdata); + mod_timer(&ifmgd->conn_mon_timer, + round_jiffies_up(jiffies + + IEEE80211_CONNECTION_IDLE_TIME)); } } @@ -1658,27 +1724,41 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, if (rx_status->freq != local->hw.conf.channel->center_freq) return; - if (WARN_ON(!ifmgd->associated)) + /* + * We might have received a number of frames, among them a + * disassoc frame and a beacon... + */ + if (!ifmgd->associated) return; bssid = ifmgd->associated->cbss.bssid; - if (WARN_ON(memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0)) + /* + * And in theory even frames from a different AP we were just + * associated to a split-second ago! + */ + if (memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0) return; - if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) { + if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG if (net_ratelimit()) { printk(KERN_DEBUG "%s: cancelling probereq poll due " "to a received beacon\n", sdata->dev->name); } #endif - ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; + ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL; mutex_lock(&local->iflist_mtx); ieee80211_recalc_ps(local, -1); mutex_unlock(&local->iflist_mtx); } + /* + * Push the beacon loss detection into the future since + * we are processing a beacon from the AP just now. + */ + mod_beacon_timer(sdata); + ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable, len - baselen, &elems, @@ -1980,6 +2060,37 @@ static void ieee80211_sta_work(struct work_struct *work) /* then process the rest of the work */ mutex_lock(&ifmgd->mtx); + if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | + IEEE80211_STA_CONNECTION_POLL) && + ifmgd->associated) { + if (time_is_after_jiffies(ifmgd->probe_timeout)) + run_again(ifmgd, ifmgd->probe_timeout); + else { + u8 bssid[ETH_ALEN]; + /* + * We actually lost the connection ... or did we? + * Let's make sure! + */ + ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | + IEEE80211_STA_BEACON_POLL); + memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN); + printk(KERN_DEBUG "No probe response from AP %pM" + " after %dms, disconnecting.\n", + bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); + ieee80211_set_disassoc(sdata); + mutex_unlock(&ifmgd->mtx); + /* + * must be outside lock due to cfg80211, + * but that's not a problem. + */ + ieee80211_send_deauth_disassoc(sdata, bssid, + IEEE80211_STYPE_DEAUTH, + WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, + NULL); + mutex_lock(&ifmgd->mtx); + } + } + list_for_each_entry(wk, &ifmgd->work_list, list) { if (wk->state != IEEE80211_MGD_STATE_IDLE) { anybusy = true; @@ -2067,15 +2178,51 @@ static void ieee80211_sta_work(struct work_struct *work) ieee80211_recalc_idle(local); } +static void ieee80211_sta_bcn_mon_timer(unsigned long data) +{ + struct ieee80211_sub_if_data *sdata = + (struct ieee80211_sub_if_data *) data; + struct ieee80211_local *local = sdata->local; + + if (local->quiescing) + return; + + queue_work(sdata->local->hw.workqueue, + &sdata->u.mgd.beacon_loss_work); +} + +static void ieee80211_sta_conn_mon_timer(unsigned long data) +{ + struct ieee80211_sub_if_data *sdata = + (struct ieee80211_sub_if_data *) data; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_local *local = sdata->local; + + if (local->quiescing) + return; + + queue_work(local->hw.workqueue, &ifmgd->monitor_work); +} + +static void ieee80211_sta_monitor_work(struct work_struct *work) +{ + struct ieee80211_sub_if_data *sdata = + container_of(work, struct ieee80211_sub_if_data, + u.mgd.monitor_work); + + ieee80211_mgd_probe_ap(sdata, false); +} + static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) { if (sdata->vif.type == NL80211_IFTYPE_STATION) { - /* - * Need to update last_beacon to avoid beacon loss - * test to trigger. - */ - sdata->u.mgd.last_beacon = jiffies; + sdata->u.mgd.flags &= ~(IEEE80211_STA_BEACON_POLL | + IEEE80211_STA_CONNECTION_POLL); + /* let's probe the connection once */ + queue_work(sdata->local->hw.workqueue, + &sdata->u.mgd.monitor_work); + /* and do all the other regular work too */ queue_work(sdata->local->hw.workqueue, &sdata->u.mgd.work); } @@ -2100,6 +2247,11 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata) cancel_work_sync(&ifmgd->chswitch_work); if (del_timer_sync(&ifmgd->chswitch_timer)) set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running); + + cancel_work_sync(&ifmgd->monitor_work); + /* these will just be re-established on connection */ + del_timer_sync(&ifmgd->conn_mon_timer); + del_timer_sync(&ifmgd->bcn_mon_timer); } void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) @@ -2120,10 +2272,15 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) ifmgd = &sdata->u.mgd; INIT_WORK(&ifmgd->work, ieee80211_sta_work); + INIT_WORK(&ifmgd->monitor_work, ieee80211_sta_monitor_work); INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); INIT_WORK(&ifmgd->beacon_loss_work, ieee80211_beacon_loss_work); setup_timer(&ifmgd->timer, ieee80211_sta_timer, (unsigned long) sdata); + setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, + (unsigned long) sdata); + setup_timer(&ifmgd->conn_mon_timer, ieee80211_sta_conn_mon_timer, + (unsigned long) sdata); setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, (unsigned long) sdata); skb_queue_head_init(&ifmgd->skb_queue); @@ -2323,7 +2480,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) { bssid = req->bss->bssid; - ieee80211_set_disassoc(sdata, bssid, true); + ieee80211_set_disassoc(sdata); } else list_for_each_entry(wk, &ifmgd->work_list, list) { if (&wk->bss->cbss == req->bss) { bssid = req->bss->bssid; @@ -2365,7 +2522,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, return -ENOLINK; } - ieee80211_set_disassoc(sdata, req->bss->bssid, false); + ieee80211_set_disassoc(sdata); mutex_unlock(&ifmgd->mtx); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index fe6b99059531..b513fb791153 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -833,28 +833,22 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) if (!sta) return RX_CONTINUE; - /* Update last_rx only for IBSS packets which are for the current - * BSSID to avoid keeping the current IBSS network alive in cases where - * other STAs are using different BSSID. */ + /* + * Update last_rx only for IBSS packets which are for the current + * BSSID to avoid keeping the current IBSS network alive in cases + * where other STAs start using different BSSID. + */ if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) { u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, NL80211_IFTYPE_ADHOC); if (compare_ether_addr(bssid, rx->sdata->u.ibss.bssid) == 0) sta->last_rx = jiffies; - } else - if (!is_multicast_ether_addr(hdr->addr1) || - rx->sdata->vif.type == NL80211_IFTYPE_STATION) { - /* Update last_rx only for unicast frames in order to prevent - * the Probe Request frames (the only broadcast frames from a - * STA in infrastructure mode) from keeping a connection alive. + } else if (!is_multicast_ether_addr(hdr->addr1)) { + /* * Mesh beacons will update last_rx when if they are found to * match the current local configuration when processed. */ - if (rx->sdata->vif.type == NL80211_IFTYPE_STATION && - ieee80211_is_beacon(hdr->frame_control)) { - rx->sdata->u.mgd.last_beacon = jiffies; - } else - sta->last_rx = jiffies; + sta->last_rx = jiffies; } if (!(rx->flags & IEEE80211_RX_RA_MATCH)) -- cgit v1.2.3 From a43816df2a1a61effcb701037bdf63621d066182 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 10 Jul 2009 11:39:26 +0200 Subject: mac80211: mesh: fix two small problems 1) there's a spin_lock() that needs to be spin_lock_bh() 2) action frames of size 24 might cause an out-of-bounds memory access (for the 25th byte only, so no big deal) Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mesh.c | 5 ++++- net/mac80211/mesh_hwmp.c | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 542ea025494e..8a97b1423088 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -685,9 +685,12 @@ ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) fc = le16_to_cpu(mgmt->frame_control); switch (fc & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_ACTION: + if (skb->len < IEEE80211_MIN_ACTION_SIZE) + return RX_DROP_MONITOR; + /* fall through */ case IEEE80211_STYPE_PROBE_RESP: case IEEE80211_STYPE_BEACON: - case IEEE80211_STYPE_ACTION: skb_queue_tail(&ifmsh->skb_queue, skb); queue_work(local->hw.workqueue, &ifmsh->work); return RX_QUEUED; diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index f49ef288e2e2..8e86e910edfc 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -686,11 +686,11 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) u8 ttl, dst_flags; u32 lifetime; - spin_lock(&ifmsh->mesh_preq_queue_lock); + spin_lock_bh(&ifmsh->mesh_preq_queue_lock); if (!ifmsh->preq_queue_len || time_before(jiffies, ifmsh->last_preq + min_preq_int_jiff(sdata))) { - spin_unlock(&ifmsh->mesh_preq_queue_lock); + spin_unlock_bh(&ifmsh->mesh_preq_queue_lock); return; } @@ -698,7 +698,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) struct mesh_preq_queue, list); list_del(&preq_node->list); --ifmsh->preq_queue_len; - spin_unlock(&ifmsh->mesh_preq_queue_lock); + spin_unlock_bh(&ifmsh->mesh_preq_queue_lock); rcu_read_lock(); mpath = mesh_path_lookup(preq_node->dst, sdata); -- cgit v1.2.3 From 0e2b6286805c419d28a4c1e19e3a121af7449b20 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 13 Jul 2009 13:23:39 +0200 Subject: mac80211: cancel the connection monitor timers/work In "mac80211: monitor the connection" I forgot to add code to cancel the new timers & work when the interface is brought down, which isn't a problem if you just bring it down, but _is_ a problem when you destroy the interface. Correct this lapse. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/iface.c | 8 +++++--- net/mac80211/mlme.c | 3 +++ 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 4839a2d97a3b..090aa5a47182 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -449,16 +449,18 @@ static int ieee80211_stop(struct net_device *dev) case NL80211_IFTYPE_STATION: del_timer_sync(&sdata->u.mgd.chswitch_timer); del_timer_sync(&sdata->u.mgd.timer); + del_timer_sync(&sdata->u.mgd.conn_mon_timer); + del_timer_sync(&sdata->u.mgd.bcn_mon_timer); /* - * If the timer fired while we waited for it, it will have - * requeued the work. Now the work will be running again + * If any of the timers fired while we waited for it, it will + * have queued its work. Now the work will be running again * but will not rearm the timer again because it checks * whether the interface is running, which, at this point, * it no longer is. */ cancel_work_sync(&sdata->u.mgd.work); cancel_work_sync(&sdata->u.mgd.chswitch_work); - + cancel_work_sync(&sdata->u.mgd.monitor_work); cancel_work_sync(&sdata->u.mgd.beacon_loss_work); /* diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 18dad229344c..e3b3156aca9e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1163,6 +1163,9 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, const u8 *ssid; bool already = false; + if (!netif_running(sdata->dev)) + return; + mutex_lock(&ifmgd->mtx); if (!ifmgd->associated) -- cgit v1.2.3 From b770b43e95a66587fbd8c1841de83da87fbf23ea Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 16 Jul 2009 10:15:09 -0700 Subject: mac80211: drop frames for sta with no valid rate When we're associated we should be able to send data to target sta. If we cannot we may be trying to use the incorrect band to talk to the sta. Lets catch any such cases, warn, and drop the frames to not invalidate assumptions being made on rate control algorithms when they have a valid sta to communicate with. Any such cases should be handled and fixed. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/mac80211/tx.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'net/mac80211') diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 60ae086995b1..f3efd4f16e91 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -512,6 +512,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) int i, len; bool inval = false, rts = false, short_preamble = false; struct ieee80211_tx_rate_control txrc; + u32 sta_flags; memset(&txrc, 0, sizeof(txrc)); @@ -544,7 +545,26 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) (tx->sta && test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE)))) txrc.short_preamble = short_preamble = true; + sta_flags = tx->sta ? get_sta_flags(tx->sta) : 0; + + /* + * Lets not bother rate control if we're associated and cannot + * talk to the sta. This should not happen. + */ + if (WARN((tx->local->sw_scanning) && + (sta_flags & WLAN_STA_ASSOC) && + !rate_usable_index_exists(sband, &tx->sta->sta), + "%s: Dropped data frame as no usable bitrate found while " + "scanning and associated. Target station: " + "%pM on %d GHz band\n", + tx->dev->name, hdr->addr1, + tx->channel->band ? 5 : 2)) + return TX_DROP; + /* + * If we're associated with the sta at this point we know we can at + * least send the frame at the lowest bit rate. + */ rate_control_get_rate(tx->sdata, tx->sta, &txrc); if (unlikely(info->control.rates[0].idx < 0)) -- cgit v1.2.3 From e8986436580caf50ebbd3bf8371074aadf95aba5 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 14 Jul 2009 20:14:06 -0400 Subject: mac80211: make minstrel/pid RC use ieee80211_is_data(fc) Cc: Felix Fietkau Cc: Derek Smithies Cc: Chittajit Mitra Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/mac80211/rc80211_minstrel.c | 7 +++---- net/mac80211/rc80211_pid_algo.c | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 37771abd8f5a..5bdce0c951dd 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -75,12 +75,11 @@ use_low_rate(struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - u16 fc; + __le16 fc; - fc = le16_to_cpu(hdr->frame_control); + fc = hdr->frame_control; - return ((info->flags & IEEE80211_TX_CTL_NO_ACK) || - (fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA); + return ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc)); } diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index a0bef767ceb5..549607703bd8 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -280,7 +280,7 @@ rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct rc_pid_sta_info *spinfo = priv_sta; int rateidx; - u16 fc; + __le16 fc; if (txrc->rts) info->control.rates[0].count = @@ -290,9 +290,8 @@ rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta, txrc->hw->conf.short_frame_max_tx_count; /* Send management frames and NO_ACK data using lowest rate. */ - fc = le16_to_cpu(hdr->frame_control); - if (!sta || !spinfo || - (fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || + fc = hdr->frame_control; + if (!sta || !spinfo || !ieee80211_is_data(fc) || info->flags & IEEE80211_TX_CTL_NO_ACK) { info->control.rates[0].idx = rate_lowest_index(sband, sta); if (info->flags & IEEE80211_TX_CTL_NO_ACK) -- cgit v1.2.3 From 4c6d4f5c33fbe19b134c1af43af166fee79eb986 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 16 Jul 2009 10:05:41 -0700 Subject: mac80211: add helper for management / no-ack frame rate decision All current rate control algorithms agree to send management and no-ack frames at the lowest rate. They also agree to do this when sta and the private rate control data is NULL. We add a hlper to mac80211 for this and simplify the rate control algorithm code. Developers wishing to make enhancements to rate control algorithms are for broadcast/multicast can opt to not use this in their gate_rate() mac80211 callback. Cc: Zhu Yi Acked-by: Reinette Chatre Cc: ipw3945-devel@lists.sourceforge.net Cc: Gabor Juhos Acked-by: Felix Fietkau Cc: Derek Smithies Cc: Chittajit Mitra Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/mac80211/rate.c | 29 +++++++++++++++++++++++++++++ net/mac80211/rc80211_minstrel.c | 22 +--------------------- net/mac80211/rc80211_pid_algo.c | 11 +---------- 3 files changed, 31 insertions(+), 31 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 4641f00a1e5c..8ac7a984d886 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -198,6 +198,35 @@ static void rate_control_release(struct kref *kref) kfree(ctrl_ref); } +static bool rc_no_data_or_no_ack(struct ieee80211_tx_rate_control *txrc) +{ + struct sk_buff *skb = txrc->skb; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + __le16 fc; + + fc = hdr->frame_control; + + return ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc)); +} + +bool rate_control_send_low(struct ieee80211_sta *sta, + void *priv_sta, + struct ieee80211_tx_rate_control *txrc) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb); + + if (!sta || !priv_sta || rc_no_data_or_no_ack(txrc)) { + info->control.rates[0].idx = rate_lowest_index(txrc->sband, sta); + info->control.rates[0].count = + (info->flags & IEEE80211_TX_CTL_NO_ACK) ? + 1 : txrc->hw->max_rate_tries; + return true; + } + return false; +} +EXPORT_SYMBOL(rate_control_send_low); + void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, struct ieee80211_tx_rate_control *txrc) diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 5bdce0c951dd..7c5142988bbb 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -70,19 +70,6 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix) return i; } -static inline bool -use_low_rate(struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - __le16 fc; - - fc = hdr->frame_control; - - return ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc)); -} - - static void minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) { @@ -231,7 +218,6 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, struct ieee80211_tx_rate_control *txrc) { struct sk_buff *skb = txrc->skb; - struct ieee80211_supported_band *sband = txrc->sband; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct minstrel_sta_info *mi = priv_sta; struct minstrel_priv *mp = priv; @@ -244,14 +230,8 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, int mrr_ndx[3]; int sample_rate; - if (!sta || !mi || use_low_rate(skb)) { - ar[0].idx = rate_lowest_index(sband, sta); - if (info->flags & IEEE80211_TX_CTL_NO_ACK) - ar[0].count = 1; - else - ar[0].count = mp->max_retry; + if (rate_control_send_low(sta, priv_sta, txrc)) return; - } mrr = mp->has_mrr && !txrc->rts && !txrc->bss_conf->use_cts_prot; diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index 549607703bd8..8c053be9dc24 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -276,11 +276,9 @@ rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta, { struct sk_buff *skb = txrc->skb; struct ieee80211_supported_band *sband = txrc->sband; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct rc_pid_sta_info *spinfo = priv_sta; int rateidx; - __le16 fc; if (txrc->rts) info->control.rates[0].count = @@ -290,15 +288,8 @@ rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta, txrc->hw->conf.short_frame_max_tx_count; /* Send management frames and NO_ACK data using lowest rate. */ - fc = hdr->frame_control; - if (!sta || !spinfo || !ieee80211_is_data(fc) || - info->flags & IEEE80211_TX_CTL_NO_ACK) { - info->control.rates[0].idx = rate_lowest_index(sband, sta); - if (info->flags & IEEE80211_TX_CTL_NO_ACK) - info->control.rates[0].count = 1; - + if (rate_control_send_low(sta, priv_sta, txrc)) return; - } rateidx = spinfo->txrate_idx; -- cgit v1.2.3 From a99d02483a40b9410d8a7af3b653ebc3f106280f Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 19 Jul 2009 22:09:32 +0200 Subject: mac80211: do not monitor the connection while scanning mac80211 constantly monitors the connection to the associated AP in order to check if it is out of reach/dead. This is absolutely fine most of the time. Except when there is a scheduled scan for the whole neighborhood. After all this path could trigger while scanning on different channel. Or even worse: this AP probing triggers a WARN_ON in rate_lowest_index when the scan code did a band transition! ( http://www.kerneloops.org/raw.php?rawid=449304 ) Reported-by: Larry Finger Signed-off-by: Christian Lamparter Tested-by: Larry Finger Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net/mac80211') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e3b3156aca9e..523c0d994d15 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2213,6 +2213,9 @@ static void ieee80211_sta_monitor_work(struct work_struct *work) container_of(work, struct ieee80211_sub_if_data, u.mgd.monitor_work); + if (sdata->local->sw_scanning || sdata->local->hw_scanning) + return; + ieee80211_mgd_probe_ap(sdata, false); } -- cgit v1.2.3 From f742880c9ca733b6c18bfaa0f5ad2a57f37180c2 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 19 Jul 2009 23:21:07 +0200 Subject: mac80211: fix spare warnings in driver-trace.h This patch fixes the following errors: driver-trace.h:148:1: error: cannot size expression driver-trace.h:148:1: error: cannot size expression [...] driver-trace.h:222:1: error: cannot size expression driver-trace.h:71:1: error: incompatible types for operation (<) driver-trace.h:71:1: left side has type void * driver-trace.h:71:1: right side has type int driver-trace.h:99:1: error: incompatible types for operation (<) driver-trace.h:99:1: left side has type void * driver-trace.h:99:1: right side has type int driver-trace.h:148:1: error: incompatible types for operation (<) driver-trace.h:148:1: left side has type void * driver-trace.h:148:1: right side has type int driver-trace.h:222:1: error: cannot size expression driver-trace.h:248:1: error: incompatible types for operation (<) driver-trace.h:248:1: left side has type void * driver-trace.h:248:1: right side has type int driver-trace.h:446:1: error: incompatible types for operation (<) driver-trace.h:446:1: left side has type void * driver-trace.h:446:1: right side has type int Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- net/mac80211/driver-trace.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 48c93d13e7b0..5a10da2d70fd 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -5,7 +5,7 @@ #include #include "ieee80211_i.h" -#ifndef CONFIG_MAC80211_DRIVER_API_TRACER +#if !defined(CONFIG_MAC80211_DRIVER_API_TRACER) || defined(__CHECKER__) #undef TRACE_EVENT #define TRACE_EVENT(name, proto, ...) \ static inline void trace_ ## name(proto) {} @@ -639,7 +639,7 @@ TRACE_EVENT(drv_ampdu_action, LOCAL_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret ) ); -#endif /* __MAC80211_DRIVER_TRACE */ +#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ #undef TRACE_INCLUDE_PATH #define TRACE_INCLUDE_PATH . -- cgit v1.2.3 From 3b8d81e020f77c9da8b85b0685c8cd2ca7c7b150 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 17 Jun 2009 17:43:56 +0200 Subject: mac80211: remove master netdev With the internal 'pending' queue system in place, we can simply put packets there instead of pushing them off to the master dev, getting rid of the master interface completely. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/agg-tx.c | 3 - net/mac80211/debugfs.c | 2 +- net/mac80211/ieee80211_i.h | 19 ++- net/mac80211/iface.c | 43 ++++--- net/mac80211/main.c | 120 +----------------- net/mac80211/rate.c | 2 +- net/mac80211/rx.c | 16 ++- net/mac80211/scan.c | 19 ++- net/mac80211/tx.c | 299 +++++++++++++++++++-------------------------- net/mac80211/util.c | 52 ++------ net/mac80211/wme.c | 6 +- net/mac80211/wme.h | 3 +- 12 files changed, 192 insertions(+), 392 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 9e5762ad307d..1958c7c42cd9 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -383,9 +383,6 @@ static void ieee80211_agg_splice_packets(struct ieee80211_local *local, if (!skb_queue_empty(&sta->ampdu_mlme.tid_tx[tid]->pending)) { spin_lock_irqsave(&local->queue_stop_reason_lock, flags); - /* mark queue as pending, it is stopped already */ - __set_bit(IEEE80211_QUEUE_STOP_REASON_PENDING, - &local->queue_stop_reasons[queue]); /* copy over remaining packets */ skb_queue_splice_tail_init( &sta->ampdu_mlme.tid_tx[tid]->pending, diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 6c439cd5ccea..96991b68f048 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -175,7 +175,7 @@ static ssize_t queues_read(struct file *file, char __user *user_buf, for (q = 0; q < local->hw.queues; q++) res += sprintf(buf + res, "%02d: %#.8lx/%d\n", q, local->queue_stop_reasons[q], - __netif_subqueue_stopped(local->mdev, q)); + skb_queue_len(&local->pending[q])); spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); return simple_read_from_buffer(user_buf, count, ppos, buf, res); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a34bca2dc52f..6a0177137dd5 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -567,14 +567,9 @@ enum queue_stop_reason { IEEE80211_QUEUE_STOP_REASON_CSA, IEEE80211_QUEUE_STOP_REASON_AGGREGATION, IEEE80211_QUEUE_STOP_REASON_SUSPEND, - IEEE80211_QUEUE_STOP_REASON_PENDING, IEEE80211_QUEUE_STOP_REASON_SKB_ADD, }; -struct ieee80211_master_priv { - struct ieee80211_local *local; -}; - struct ieee80211_local { /* embed the driver visible part. * don't cast (use the static inlines below), but we keep @@ -587,13 +582,20 @@ struct ieee80211_local { /* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */ spinlock_t queue_stop_reason_lock; - struct net_device *mdev; /* wmaster# - "master" 802.11 device */ int open_count; int monitors, cooked_mntrs; /* number of interfaces with corresponding FIF_ flags */ int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss; unsigned int filter_flags; /* FIF_* */ struct iw_statistics wstats; + + /* protects the aggregated multicast list and filter calls */ + spinlock_t filter_lock; + + /* aggregated multicast list */ + struct dev_addr_list *mc_list; + int mc_count; + bool tim_in_locked_section; /* see ieee80211_beacon_get() */ /* @@ -813,10 +815,6 @@ struct ieee80211_local { static inline struct ieee80211_sub_if_data * IEEE80211_DEV_TO_SUB_IF(struct net_device *dev) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - BUG_ON(!local || local->mdev == dev); - return netdev_priv(dev); } @@ -996,7 +994,6 @@ void ieee80211_recalc_idle(struct ieee80211_local *local); /* tx handling */ void ieee80211_clear_tx_pending(struct ieee80211_local *local); void ieee80211_tx_pending(unsigned long data); -int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev); int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev); int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 090aa5a47182..2f797a86ced5 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -190,10 +190,6 @@ static int ieee80211_open(struct net_device *dev) ETH_ALEN); } - if (compare_ether_addr(null_addr, local->mdev->dev_addr) == 0) - memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr, - ETH_ALEN); - /* * Validate the MAC address for this device. */ @@ -229,9 +225,9 @@ static int ieee80211_open(struct net_device *dev) if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) local->fif_other_bss++; - netif_addr_lock_bh(local->mdev); + spin_lock_bh(&local->filter_lock); ieee80211_configure_filter(local); - netif_addr_unlock_bh(local->mdev); + spin_unlock_bh(&local->filter_lock); break; default: conf.vif = &sdata->vif; @@ -243,9 +239,9 @@ static int ieee80211_open(struct net_device *dev) if (ieee80211_vif_is_mesh(&sdata->vif)) { local->fif_other_bss++; - netif_addr_lock_bh(local->mdev); + spin_lock_bh(&local->filter_lock); ieee80211_configure_filter(local); - netif_addr_unlock_bh(local->mdev); + spin_unlock_bh(&local->filter_lock); ieee80211_start_mesh(sdata); } @@ -279,10 +275,6 @@ static int ieee80211_open(struct net_device *dev) } if (local->open_count == 0) { - res = dev_open(local->mdev); - WARN_ON(res); - if (res) - goto err_del_interface; tasklet_enable(&local->tx_pending_tasklet); tasklet_enable(&local->tasklet); } @@ -393,7 +385,14 @@ static int ieee80211_stop(struct net_device *dev) if (sdata->flags & IEEE80211_SDATA_PROMISC) atomic_dec(&local->iff_promiscs); - dev_mc_unsync(local->mdev, dev); + netif_addr_lock_bh(dev); + spin_lock_bh(&local->filter_lock); + __dev_addr_unsync(&local->mc_list, &local->mc_count, + &dev->mc_list, &dev->mc_count); + ieee80211_configure_filter(local); + spin_unlock_bh(&local->filter_lock); + netif_addr_unlock_bh(dev); + del_timer_sync(&local->dynamic_ps_timer); cancel_work_sync(&local->dynamic_ps_enable_work); @@ -442,9 +441,9 @@ static int ieee80211_stop(struct net_device *dev) if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) local->fif_other_bss--; - netif_addr_lock_bh(local->mdev); + spin_lock_bh(&local->filter_lock); ieee80211_configure_filter(local); - netif_addr_unlock_bh(local->mdev); + spin_unlock_bh(&local->filter_lock); break; case NL80211_IFTYPE_STATION: del_timer_sync(&sdata->u.mgd.chswitch_timer); @@ -487,9 +486,9 @@ static int ieee80211_stop(struct net_device *dev) local->fif_other_bss--; atomic_dec(&local->iff_allmultis); - netif_addr_lock_bh(local->mdev); + spin_lock_bh(&local->filter_lock); ieee80211_configure_filter(local); - netif_addr_unlock_bh(local->mdev); + spin_unlock_bh(&local->filter_lock); ieee80211_stop_mesh(sdata); } @@ -535,9 +534,6 @@ static int ieee80211_stop(struct net_device *dev) ieee80211_recalc_ps(local, -1); if (local->open_count == 0) { - if (netif_running(local->mdev)) - dev_close(local->mdev); - drv_stop(local); ieee80211_led_radio(local, false); @@ -584,8 +580,11 @@ static void ieee80211_set_multicast_list(struct net_device *dev) atomic_dec(&local->iff_promiscs); sdata->flags ^= IEEE80211_SDATA_PROMISC; } - - dev_mc_sync(local->mdev, dev); + spin_lock_bh(&local->filter_lock); + __dev_addr_sync(&local->mc_list, &local->mc_count, + &dev->mc_list, &dev->mc_count); + ieee80211_configure_filter(local); + spin_unlock_bh(&local->filter_lock); } /* diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 5b69f5f07299..3234f3751d22 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -83,75 +83,14 @@ void ieee80211_configure_filter(struct ieee80211_local *local) new_flags |= (1<<31); drv_configure_filter(local, changed_flags, &new_flags, - local->mdev->mc_count, - local->mdev->mc_list); + local->mc_count, + local->mc_list); WARN_ON(new_flags & (1<<31)); local->filter_flags = new_flags & ~(1<<31); } -/* master interface */ - -static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr) -{ - memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ - return ETH_ALEN; -} - -static const struct header_ops ieee80211_header_ops = { - .create = eth_header, - .parse = header_parse_80211, - .rebuild = eth_rebuild_header, - .cache = eth_header_cache, - .cache_update = eth_header_cache_update, -}; - -static int ieee80211_master_open(struct net_device *dev) -{ - struct ieee80211_master_priv *mpriv = netdev_priv(dev); - struct ieee80211_local *local = mpriv->local; - struct ieee80211_sub_if_data *sdata; - int res = -EOPNOTSUPP; - - /* we hold the RTNL here so can safely walk the list */ - list_for_each_entry(sdata, &local->interfaces, list) { - if (netif_running(sdata->dev)) { - res = 0; - break; - } - } - - if (res) - return res; - - netif_tx_start_all_queues(local->mdev); - - return 0; -} - -static int ieee80211_master_stop(struct net_device *dev) -{ - struct ieee80211_master_priv *mpriv = netdev_priv(dev); - struct ieee80211_local *local = mpriv->local; - struct ieee80211_sub_if_data *sdata; - - /* we hold the RTNL here so can safely walk the list */ - list_for_each_entry(sdata, &local->interfaces, list) - if (netif_running(sdata->dev)) - dev_close(sdata->dev); - - return 0; -} - -static void ieee80211_master_set_multicast_list(struct net_device *dev) -{ - struct ieee80211_master_priv *mpriv = netdev_priv(dev); - struct ieee80211_local *local = mpriv->local; - - ieee80211_configure_filter(local); -} - int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) { struct ieee80211_channel *chan, *scan_chan; @@ -310,7 +249,6 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int tmp; - skb->dev = local->mdev; skb->pkt_type = IEEE80211_TX_STATUS_MSG; skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ? &local->skb_queue : &local->skb_queue_unreliable, skb); @@ -716,7 +654,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, mutex_init(&local->scan_mtx); spin_lock_init(&local->key_lock); - + spin_lock_init(&local->filter_lock); spin_lock_init(&local->queue_stop_reason_lock); INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); @@ -752,30 +690,11 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, } EXPORT_SYMBOL(ieee80211_alloc_hw); -static const struct net_device_ops ieee80211_master_ops = { - .ndo_start_xmit = ieee80211_master_start_xmit, - .ndo_open = ieee80211_master_open, - .ndo_stop = ieee80211_master_stop, - .ndo_set_multicast_list = ieee80211_master_set_multicast_list, - .ndo_select_queue = ieee80211_select_queue, -}; - -static void ieee80211_master_setup(struct net_device *mdev) -{ - mdev->type = ARPHRD_IEEE80211; - mdev->netdev_ops = &ieee80211_master_ops; - mdev->header_ops = &ieee80211_header_ops; - mdev->tx_queue_len = 1000; - mdev->addr_len = ETH_ALEN; -} - int ieee80211_register_hw(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); int result; enum ieee80211_band band; - struct net_device *mdev; - struct ieee80211_master_priv *mpriv; int channels, i, j, max_bitrates; bool supp_ht; static const u32 cipher_suites[] = { @@ -874,16 +793,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (hw->queues > IEEE80211_MAX_QUEUES) hw->queues = IEEE80211_MAX_QUEUES; - mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv), - "wmaster%d", ieee80211_master_setup, - hw->queues); - if (!mdev) - goto fail_mdev_alloc; - - mpriv = netdev_priv(mdev); - mpriv->local = local; - local->mdev = mdev; - local->hw.workqueue = create_singlethread_workqueue(wiphy_name(local->hw.wiphy)); if (!local->hw.workqueue) { @@ -918,17 +827,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) } rtnl_lock(); - result = dev_alloc_name(local->mdev, local->mdev->name); - if (result < 0) - goto fail_dev; - - memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); - SET_NETDEV_DEV(local->mdev, wiphy_dev(local->hw.wiphy)); - local->mdev->features |= NETIF_F_NETNS_LOCAL; - - result = register_netdevice(local->mdev); - if (result < 0) - goto fail_dev; result = ieee80211_init_rate_ctrl_alg(local, hw->rate_control_algorithm); @@ -981,9 +879,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) ieee80211_led_exit(local); ieee80211_remove_interfaces(local); fail_rate: - unregister_netdevice(local->mdev); - local->mdev = NULL; - fail_dev: rtnl_unlock(); ieee80211_wep_free(local); fail_wep: @@ -992,9 +887,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) debugfs_hw_del(local); destroy_workqueue(local->hw.workqueue); fail_workqueue: - if (local->mdev) - free_netdev(local->mdev); - fail_mdev_alloc: wiphy_unregister(local->hw.wiphy); fail_wiphy_register: kfree(local->int_scan_req.channels); @@ -1019,13 +911,8 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) * because the driver cannot be handing us frames any * more and the tasklet is killed. */ - - /* First, we remove all virtual interfaces. */ ieee80211_remove_interfaces(local); - /* then, finally, remove the master interface */ - unregister_netdevice(local->mdev); - rtnl_unlock(); ieee80211_clear_tx_pending(local); @@ -1044,7 +931,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) wiphy_unregister(local->hw.wiphy); ieee80211_wep_free(local); ieee80211_led_exit(local); - free_netdev(local->mdev); kfree(local->int_scan_req.channels); } EXPORT_SYMBOL(ieee80211_unregister_hw); diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 8ac7a984d886..b33efc4fc267 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -287,7 +287,7 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, struct rate_control_ref *ref, *old; ASSERT_RTNL(); - if (local->open_count || netif_running(local->mdev)) + if (local->open_count) return -EBUSY; ref = rate_control_alloc(name, local); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b513fb791153..7f33f775c5df 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1478,6 +1478,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) struct ieee80211s_hdr *mesh_hdr; unsigned int hdrlen; struct sk_buff *skb = rx->skb, *fwd_skb; + struct ieee80211_local *local = rx->local; hdr = (struct ieee80211_hdr *) skb->data; hdrlen = ieee80211_hdrlen(hdr->frame_control); @@ -1520,6 +1521,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) dropped_frames_ttl); else { struct ieee80211_hdr *fwd_hdr; + struct ieee80211_tx_info *info; + fwd_skb = skb_copy(skb, GFP_ATOMIC); if (!fwd_skb && net_ratelimit()) @@ -1533,9 +1536,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) */ memcpy(fwd_hdr->addr1, fwd_hdr->addr2, ETH_ALEN); memcpy(fwd_hdr->addr2, rx->dev->dev_addr, ETH_ALEN); - fwd_skb->dev = rx->local->mdev; + info = IEEE80211_SKB_CB(fwd_skb); + memset(info, 0, sizeof(*info)); + info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; fwd_skb->iif = rx->dev->ifindex; - dev_queue_xmit(fwd_skb); + ieee80211_select_queue(local, fwd_skb); + ieee80211_add_pending_skb(local, fwd_skb); } } @@ -1803,8 +1809,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) return RX_DROP_MONITOR; } -static void ieee80211_rx_michael_mic_report(struct net_device *dev, - struct ieee80211_hdr *hdr, +static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr, struct ieee80211_rx_data *rx) { int keyidx; @@ -2114,7 +2119,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, } if ((status->flag & RX_FLAG_MMIC_ERROR)) { - ieee80211_rx_michael_mic_report(local->mdev, hdr, &rx); + ieee80211_rx_michael_mic_report(hdr, &rx); return; } @@ -2483,7 +2488,6 @@ void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb) BUILD_BUG_ON(sizeof(struct ieee80211_rx_status) > sizeof(skb->cb)); - skb->dev = local->mdev; skb->pkt_type = IEEE80211_RX_MSG; skb_queue_tail(&local->skb_queue, skb); tasklet_schedule(&local->tasklet); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 5f4f7869d050..74820656dc89 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -294,16 +294,13 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) if (was_hw_scan) goto done; - netif_tx_lock_bh(local->mdev); - netif_addr_lock(local->mdev); + spin_lock_bh(&local->filter_lock); local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC; drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC, &local->filter_flags, - local->mdev->mc_count, - local->mdev->mc_list); - - netif_addr_unlock(local->mdev); - netif_tx_unlock_bh(local->mdev); + local->mc_count, + local->mc_list); + spin_unlock_bh(&local->filter_lock); drv_sw_scan_complete(local); @@ -382,13 +379,13 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) local->scan_state = SCAN_SET_CHANNEL; local->scan_channel_idx = 0; - netif_addr_lock_bh(local->mdev); + spin_lock_bh(&local->filter_lock); local->filter_flags |= FIF_BCN_PRBRESP_PROMISC; drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC, &local->filter_flags, - local->mdev->mc_count, - local->mdev->mc_list); - netif_addr_unlock_bh(local->mdev); + local->mc_count, + local->mc_list); + spin_unlock_bh(&local->filter_lock); /* TODO: start scan as soon as all nullfunc frames are ACKed */ queue_delayed_work(local->hw.workqueue, &local->scan_work, diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index f3efd4f16e91..7adaeb2c53e8 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -451,7 +451,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; - if (unlikely(tx->skb->do_not_encrypt)) + if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) tx->key = NULL; else if (tx->sta && (key = rcu_dereference(tx->sta->key))) tx->key = key; @@ -497,7 +497,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) } if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) - tx->skb->do_not_encrypt = 1; + info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; return TX_CONTINUE; } @@ -774,9 +774,7 @@ static int ieee80211_fragment(struct ieee80211_local *local, memcpy(tmp->cb, skb->cb, sizeof(tmp->cb)); skb_copy_queue_mapping(tmp, skb); tmp->priority = skb->priority; - tmp->do_not_encrypt = skb->do_not_encrypt; tmp->dev = skb->dev; - tmp->iif = skb->iif; /* copy header and data */ memcpy(skb_put(tmp, hdrlen), skb->data, hdrlen); @@ -804,7 +802,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) /* * Warn when submitting a fragmented A-MPDU frame and drop it. - * This scenario is handled in __ieee80211_tx_prepare but extra + * This scenario is handled in ieee80211_tx_prepare but extra * caution taken here as fragmented ampdu may cause Tx stop. */ if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU)) @@ -943,11 +941,12 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, struct ieee80211_radiotap_header *rthdr = (struct ieee80211_radiotap_header *) skb->data; struct ieee80211_supported_band *sband; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); sband = tx->local->hw.wiphy->bands[tx->channel->band]; - skb->do_not_encrypt = 1; + info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; tx->flags &= ~IEEE80211_TX_FRAGMENTED; /* @@ -985,7 +984,7 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, skb_trim(skb, skb->len - FCS_LEN); } if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP) - tx->skb->do_not_encrypt = 0; + info->flags &= ~IEEE80211_TX_INTFL_DONT_ENCRYPT; if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG) tx->flags |= IEEE80211_TX_FRAGMENTED; break; @@ -1018,13 +1017,12 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, * initialises @tx */ static ieee80211_tx_result -__ieee80211_tx_prepare(struct ieee80211_tx_data *tx, - struct sk_buff *skb, - struct net_device *dev) +ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, + struct ieee80211_tx_data *tx, + struct sk_buff *skb) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_local *local = sdata->local; struct ieee80211_hdr *hdr; - struct ieee80211_sub_if_data *sdata; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int hdrlen, tid; u8 *qc, *state; @@ -1032,9 +1030,9 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, memset(tx, 0, sizeof(*tx)); tx->skb = skb; - tx->dev = dev; /* use original interface */ + tx->dev = sdata->dev; /* use original interface */ tx->local = local; - tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev); + tx->sdata = sdata; tx->channel = local->hw.conf.channel; /* * Set this flag (used below to indicate "automatic fragmentation"), @@ -1043,7 +1041,6 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, tx->flags |= IEEE80211_TX_FRAGMENTED; /* process and remove the injection radiotap header */ - sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) { if (!__ieee80211_parse_tx_radiotap(tx, skb)) return TX_DROP; @@ -1139,50 +1136,28 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, return TX_CONTINUE; } -/* - * NB: @tx is uninitialised when passed in here - */ -static int ieee80211_tx_prepare(struct ieee80211_local *local, - struct ieee80211_tx_data *tx, - struct sk_buff *skb) -{ - struct net_device *dev; - - dev = dev_get_by_index(&init_net, skb->iif); - if (unlikely(dev && !is_ieee80211_device(local, dev))) { - dev_put(dev); - dev = NULL; - } - if (unlikely(!dev)) - return -ENODEV; - /* - * initialises tx with control - * - * return value is safe to ignore here because this function - * can only be invoked for multicast frames - * - * XXX: clean up - */ - __ieee80211_tx_prepare(tx, skb, dev); - dev_put(dev); - return 0; -} - static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff **skbp, - struct sta_info *sta) + struct sta_info *sta, + bool txpending) { struct sk_buff *skb = *skbp, *next; struct ieee80211_tx_info *info; + unsigned long flags; int ret, len; bool fragm = false; - local->mdev->trans_start = jiffies; - while (skb) { - if (ieee80211_queue_stopped(&local->hw, - skb_get_queue_mapping(skb))) - return IEEE80211_TX_PENDING; + int q = skb_get_queue_mapping(skb); + + spin_lock_irqsave(&local->queue_stop_reason_lock, flags); + ret = IEEE80211_TX_OK; + if (local->queue_stop_reasons[q] || + (!txpending && !skb_queue_empty(&local->pending[q]))) + ret = IEEE80211_TX_PENDING; + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); + if (ret != IEEE80211_TX_OK) + return ret; info = IEEE80211_SKB_CB(skb); @@ -1254,10 +1229,10 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) return 0; } -static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb, - bool txpending) +static void ieee80211_tx(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb, bool txpending) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_local *local = sdata->local; struct ieee80211_tx_data tx; ieee80211_tx_result res_prepare; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -1268,8 +1243,6 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb, queue = skb_get_queue_mapping(skb); - WARN_ON(!txpending && !skb_queue_empty(&local->pending[queue])); - if (unlikely(skb->len < 10)) { dev_kfree_skb(skb); return; @@ -1278,7 +1251,7 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb, rcu_read_lock(); /* initialises tx */ - res_prepare = __ieee80211_tx_prepare(&tx, skb, dev); + res_prepare = ieee80211_tx_prepare(sdata, &tx, skb); if (unlikely(res_prepare == TX_DROP)) { dev_kfree_skb(skb); @@ -1297,7 +1270,7 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb, retries = 0; retry: - ret = __ieee80211_tx(local, &tx.skb, tx.sta); + ret = __ieee80211_tx(local, &tx.skb, tx.sta, txpending); switch (ret) { case IEEE80211_TX_OK: break; @@ -1315,34 +1288,35 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb, spin_lock_irqsave(&local->queue_stop_reason_lock, flags); - if (__netif_subqueue_stopped(local->mdev, queue)) { + if (local->queue_stop_reasons[queue] || + !skb_queue_empty(&local->pending[queue])) { + /* + * if queue is stopped, queue up frames for later + * transmission from the tasklet + */ do { next = skb->next; skb->next = NULL; if (unlikely(txpending)) - skb_queue_head(&local->pending[queue], - skb); + __skb_queue_head(&local->pending[queue], + skb); else - skb_queue_tail(&local->pending[queue], - skb); + __skb_queue_tail(&local->pending[queue], + skb); } while ((skb = next)); - /* - * Make sure nobody will enable the queue on us - * (without going through the tasklet) nor disable the - * netdev queue underneath the pending handling code. - */ - __set_bit(IEEE80211_QUEUE_STOP_REASON_PENDING, - &local->queue_stop_reasons[queue]); - spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); } else { + /* + * otherwise retry, but this is a race condition or + * a driver bug (which we warn about if it persists) + */ spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); retries++; - if (WARN(retries > 10, "tx refused but queue active")) + if (WARN(retries > 10, "tx refused but queue active\n")) goto drop; goto retry; } @@ -1403,14 +1377,13 @@ static int ieee80211_skb_resize(struct ieee80211_local *local, return 0; } -int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) +static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb) { - struct ieee80211_master_priv *mpriv = netdev_priv(dev); - struct ieee80211_local *local = mpriv->local; + struct ieee80211_local *local = sdata->local; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - struct net_device *odev = NULL; - struct ieee80211_sub_if_data *osdata; + struct ieee80211_sub_if_data *tmp_sdata; int headroom; bool may_encrypt; enum { @@ -1419,20 +1392,7 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) UNKNOWN_ADDRESS, } monitor_iface = NOT_MONITOR; - if (skb->iif) - odev = dev_get_by_index(&init_net, skb->iif); - if (unlikely(odev && !is_ieee80211_device(local, odev))) { - dev_put(odev); - odev = NULL; - } - if (unlikely(!odev)) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: Discarded packet with nonexistent " - "originating device\n", dev->name); -#endif - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } + dev_hold(sdata->dev); if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && local->hw.conf.dynamic_ps_timeout > 0 && @@ -1448,26 +1408,21 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); } - memset(info, 0, sizeof(*info)); - info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; - osdata = IEEE80211_DEV_TO_SUB_IF(odev); - - if (ieee80211_vif_is_mesh(&osdata->vif) && + if (ieee80211_vif_is_mesh(&sdata->vif) && ieee80211_is_data(hdr->frame_control)) { if (is_multicast_ether_addr(hdr->addr3)) memcpy(hdr->addr1, hdr->addr3, ETH_ALEN); else - if (mesh_nexthop_lookup(skb, osdata)) { - dev_put(odev); - return NETDEV_TX_OK; + if (mesh_nexthop_lookup(skb, sdata)) { + dev_put(sdata->dev); + return; } - if (memcmp(odev->dev_addr, hdr->addr4, ETH_ALEN) != 0) - IEEE80211_IFSTA_MESH_CTR_INC(&osdata->u.mesh, - fwded_frames); - } else if (unlikely(osdata->vif.type == NL80211_IFTYPE_MONITOR)) { - struct ieee80211_sub_if_data *sdata; + if (memcmp(sdata->dev->dev_addr, hdr->addr4, ETH_ALEN) != 0) + IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, + fwded_frames); + } else if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) { int hdrlen; u16 len_rthdr; @@ -1491,19 +1446,17 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) */ rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, + list_for_each_entry_rcu(tmp_sdata, &local->interfaces, list) { - if (!netif_running(sdata->dev)) + if (!netif_running(tmp_sdata->dev)) continue; - if (sdata->vif.type != NL80211_IFTYPE_AP) + if (tmp_sdata->vif.type != NL80211_IFTYPE_AP) continue; - if (compare_ether_addr(sdata->dev->dev_addr, + if (compare_ether_addr(tmp_sdata->dev->dev_addr, hdr->addr2)) { - dev_hold(sdata->dev); - dev_put(odev); - osdata = sdata; - odev = osdata->dev; - skb->iif = sdata->dev->ifindex; + dev_hold(tmp_sdata->dev); + dev_put(sdata->dev); + sdata = tmp_sdata; monitor_iface = FOUND_SDATA; break; } @@ -1512,31 +1465,31 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) } } - may_encrypt = !skb->do_not_encrypt; + may_encrypt = !(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT); - headroom = osdata->local->tx_headroom; + headroom = local->tx_headroom; if (may_encrypt) headroom += IEEE80211_ENCRYPT_HEADROOM; headroom -= skb_headroom(skb); headroom = max_t(int, 0, headroom); - if (ieee80211_skb_resize(osdata->local, skb, headroom, may_encrypt)) { + if (ieee80211_skb_resize(local, skb, headroom, may_encrypt)) { dev_kfree_skb(skb); - dev_put(odev); - return NETDEV_TX_OK; + dev_put(sdata->dev); + return; } - if (osdata->vif.type == NL80211_IFTYPE_AP_VLAN) - osdata = container_of(osdata->bss, - struct ieee80211_sub_if_data, - u.ap); + tmp_sdata = sdata; + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + tmp_sdata = container_of(sdata->bss, + struct ieee80211_sub_if_data, + u.ap); if (likely(monitor_iface != UNKNOWN_ADDRESS)) - info->control.vif = &osdata->vif; - - ieee80211_tx(odev, skb, false); - dev_put(odev); + info->control.vif = &tmp_sdata->vif; - return NETDEV_TX_OK; + ieee80211_select_queue(local, skb); + ieee80211_tx(sdata, skb, false); + dev_put(sdata->dev); } int ieee80211_monitor_start_xmit(struct sk_buff *skb, @@ -1546,6 +1499,7 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct ieee80211_channel *chan = local->hw.conf.channel; struct ieee80211_radiotap_header *prthdr = (struct ieee80211_radiotap_header *)skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); u16 len_rthdr; /* @@ -1583,15 +1537,9 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb, if (unlikely(skb->len < len_rthdr)) goto fail; /* skb too short for claimed rt header extent */ - skb->dev = local->mdev; - /* needed because we set skb device to master */ skb->iif = dev->ifindex; - /* sometimes we do encrypt injected frames, will be fixed - * up in radiotap parser if not wanted */ - skb->do_not_encrypt = 0; - /* * fix up the pointers accounting for the radiotap * header still being in there. We are being given @@ -1606,8 +1554,10 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb, skb_set_network_header(skb, len_rthdr); skb_set_transport_header(skb, len_rthdr); - /* pass the radiotap header up to the next stage intact */ - dev_queue_xmit(skb); + memset(info, 0, sizeof(*info)); + + /* pass the radiotap header up to xmit */ + ieee80211_xmit(IEEE80211_DEV_TO_SUB_IF(dev), skb); return NETDEV_TX_OK; fail: @@ -1635,6 +1585,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = sdata->local; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int ret = NETDEV_TX_BUSY, head_need; u16 ethertype, hdrlen, meshhdrlen = 0; __le16 fc; @@ -1864,7 +1815,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, skb->iif = dev->ifindex; - skb->dev = local->mdev; dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; @@ -1875,8 +1825,10 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, skb_set_network_header(skb, nh_pos); skb_set_transport_header(skb, h_pos); + memset(info, 0, sizeof(*info)); + dev->trans_start = jiffies; - dev_queue_xmit(skb); + ieee80211_xmit(sdata, skb); return NETDEV_TX_OK; @@ -1918,7 +1870,6 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, return true; } - /* validate info->control.vif against skb->iif */ sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) sdata = container_of(sdata->bss, @@ -1932,12 +1883,13 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, } if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) { - ieee80211_tx(dev, skb, true); + /* do not use sdata, it may have been changed above */ + ieee80211_tx(IEEE80211_DEV_TO_SUB_IF(dev), skb, true); } else { hdr = (struct ieee80211_hdr *)skb->data; sta = sta_info_get(local, hdr->addr1); - ret = __ieee80211_tx(local, &skb, sta); + ret = __ieee80211_tx(local, &skb, sta, true); if (ret != IEEE80211_TX_OK) result = false; } @@ -1949,59 +1901,43 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, } /* - * Transmit all pending packets. Called from tasklet, locks master device - * TX lock so that no new packets can come in. + * Transmit all pending packets. Called from tasklet. */ void ieee80211_tx_pending(unsigned long data) { struct ieee80211_local *local = (struct ieee80211_local *)data; - struct net_device *dev = local->mdev; unsigned long flags; int i; - bool next; + bool txok; rcu_read_lock(); - netif_tx_lock_bh(dev); + spin_lock_irqsave(&local->queue_stop_reason_lock, flags); for (i = 0; i < local->hw.queues; i++) { /* * If queue is stopped by something other than due to pending * frames, or we have no pending frames, proceed to next queue. */ - spin_lock_irqsave(&local->queue_stop_reason_lock, flags); - next = false; - if (local->queue_stop_reasons[i] != - BIT(IEEE80211_QUEUE_STOP_REASON_PENDING) || + if (local->queue_stop_reasons[i] || skb_queue_empty(&local->pending[i])) - next = true; - spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); - - if (next) continue; - /* - * start the queue now to allow processing our packets, - * we're under the tx lock here anyway so nothing will - * happen as a result of this - */ - netif_start_subqueue(local->mdev, i); - while (!skb_queue_empty(&local->pending[i])) { - struct sk_buff *skb = skb_dequeue(&local->pending[i]); - - if (!ieee80211_tx_pending_skb(local, skb)) { - skb_queue_head(&local->pending[i], skb); + struct sk_buff *skb = __skb_dequeue(&local->pending[i]); + spin_unlock_irqrestore(&local->queue_stop_reason_lock, + flags); + + txok = ieee80211_tx_pending_skb(local, skb); + if (!txok) + __skb_queue_head(&local->pending[i], skb); + spin_lock_irqsave(&local->queue_stop_reason_lock, + flags); + if (!txok) break; - } } - - /* Start regular packet processing again. */ - if (skb_queue_empty(&local->pending[i])) - ieee80211_wake_queue_by_reason(&local->hw, i, - IEEE80211_QUEUE_STOP_REASON_PENDING); } + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); - netif_tx_unlock_bh(dev); rcu_read_unlock(); } @@ -2176,8 +2112,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, info = IEEE80211_SKB_CB(skb); - skb->do_not_encrypt = 1; - + info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; info->band = band; /* * XXX: For now, always use the lowest rate @@ -2248,9 +2183,6 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, sdata = vif_to_sdata(vif); bss = &sdata->u.ap; - if (!bss) - return NULL; - rcu_read_lock(); beacon = rcu_dereference(bss->beacon); @@ -2276,7 +2208,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, cpu_to_le16(IEEE80211_FCTL_MOREDATA); } - if (!ieee80211_tx_prepare(local, &tx, skb)) + if (!ieee80211_tx_prepare(sdata, &tx, skb)) break; dev_kfree_skb_any(skb); } @@ -2296,3 +2228,18 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, return skb; } EXPORT_SYMBOL(ieee80211_get_buffered_bc); + +void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, + int encrypt) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + skb_set_mac_header(skb, 0); + skb_set_network_header(skb, 0); + skb_set_transport_header(skb, 0); + + skb->iif = sdata->dev->ifindex; + if (!encrypt) + info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + + ieee80211_xmit(sdata, skb); +} diff --git a/net/mac80211/util.c b/net/mac80211/util.c index dbf66b52d38c..7fc55846d601 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -275,16 +275,12 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, __clear_bit(reason, &local->queue_stop_reasons[queue]); - if (!skb_queue_empty(&local->pending[queue]) && - local->queue_stop_reasons[queue] == - BIT(IEEE80211_QUEUE_STOP_REASON_PENDING)) - tasklet_schedule(&local->tx_pending_tasklet); - if (local->queue_stop_reasons[queue] != 0) /* someone still has this queue stopped */ return; - netif_wake_subqueue(local->mdev, queue); + if (!skb_queue_empty(&local->pending[queue])) + tasklet_schedule(&local->tx_pending_tasklet); } void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, @@ -313,14 +309,6 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, if (WARN_ON(queue >= hw->queues)) return; - /* - * Only stop if it was previously running, this is necessary - * for correct pending packets handling because there we may - * start (but not wake) the queue and rely on that. - */ - if (!local->queue_stop_reasons[queue]) - netif_stop_subqueue(local->mdev, queue); - __set_bit(reason, &local->queue_stop_reasons[queue]); } @@ -351,8 +339,7 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local, spin_lock_irqsave(&local->queue_stop_reason_lock, flags); __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); - __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_PENDING); - skb_queue_tail(&local->pending[queue], skb); + __skb_queue_tail(&local->pending[queue], skb); __ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); } @@ -373,16 +360,12 @@ int ieee80211_add_pending_skbs(struct ieee80211_local *local, while ((skb = skb_dequeue(skbs))) { ret++; queue = skb_get_queue_mapping(skb); - skb_queue_tail(&local->pending[queue], skb); + __skb_queue_tail(&local->pending[queue], skb); } - for (i = 0; i < hw->queues; i++) { - if (ret) - __ieee80211_stop_queue(hw, i, - IEEE80211_QUEUE_STOP_REASON_PENDING); + for (i = 0; i < hw->queues; i++) __ieee80211_wake_queue(hw, i, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); - } spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); return ret; @@ -413,11 +396,16 @@ EXPORT_SYMBOL(ieee80211_stop_queues); int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue) { struct ieee80211_local *local = hw_to_local(hw); + unsigned long flags; + int ret; if (WARN_ON(queue >= hw->queues)) return true; - return __netif_subqueue_stopped(local->mdev, queue); + spin_lock_irqsave(&local->queue_stop_reason_lock, flags); + ret = !!local->queue_stop_reasons[queue]; + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); + return ret; } EXPORT_SYMBOL(ieee80211_queue_stopped); @@ -761,20 +749,6 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, ieee80211_set_wmm_default(sdata); } -void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, - int encrypt) -{ - skb->dev = sdata->local->mdev; - skb_set_mac_header(skb, 0); - skb_set_network_header(skb, 0); - skb_set_transport_header(skb, 0); - - skb->iif = sdata->dev->ifindex; - skb->do_not_encrypt = !encrypt; - - dev_queue_xmit(skb); -} - u32 ieee80211_mandatory_rates(struct ieee80211_local *local, enum ieee80211_band band) { @@ -1049,9 +1023,9 @@ int ieee80211_reconfig(struct ieee80211_local *local) /* reconfigure hardware */ ieee80211_hw_config(local, ~0); - netif_addr_lock_bh(local->mdev); + spin_lock_bh(&local->filter_lock); ieee80211_configure_filter(local); - netif_addr_unlock_bh(local->mdev); + spin_unlock_bh(&local->filter_lock); /* Finally also reconfigure all the BSS information */ list_for_each_entry(sdata, &local->interfaces, list) { diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 116a923b14d6..b19b7696f3a2 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -85,10 +85,8 @@ static u16 classify80211(struct ieee80211_local *local, struct sk_buff *skb) return ieee802_1d_to_ac[skb->priority]; } -u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb) +void ieee80211_select_queue(struct ieee80211_local *local, struct sk_buff *skb) { - struct ieee80211_master_priv *mpriv = netdev_priv(dev); - struct ieee80211_local *local = mpriv->local; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; u16 queue; u8 tid; @@ -113,5 +111,5 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb) *p = 0; } - return queue; + skb_set_queue_mapping(skb, queue); } diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h index 7520d2e014dc..d4fd87ca5118 100644 --- a/net/mac80211/wme.h +++ b/net/mac80211/wme.h @@ -20,6 +20,7 @@ extern const int ieee802_1d_to_ac[8]; -u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb); +void ieee80211_select_queue(struct ieee80211_local *local, + struct sk_buff *skb); #endif /* _WME_H */ -- cgit v1.2.3 From 3d34deb6737b1ae1f8b7817b57d603807f5d88ea Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 18 Jun 2009 17:25:11 +0200 Subject: mac80211: fix ieee80211_xmit call context ieee80211_xmit() cannot be called with tasklets enabled because it is normally called from within a tasklet. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/tx.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'net/mac80211') diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 7adaeb2c53e8..a204092e8356 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2241,5 +2241,12 @@ void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, if (!encrypt) info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + /* + * The other path calling ieee80211_xmit is from the tasklet, + * and while we can handle concurrent transmissions locking + * requirements are that we do not come into tx with bhs on. + */ + local_bh_disable(); ieee80211_xmit(sdata, skb); + local_bh_enable(); } -- cgit v1.2.3 From 249b405cf8145da8a74b70544ae1079d244bdb00 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Tue, 7 Jul 2009 10:55:03 -0700 Subject: mac80211: Fix regression in mesh forwarding path. The removal of the master netdev broke the mesh forwarding path. This patch fixes it by using the new internal 'pending' queue. As a result of this change, mesh forwarding no longer does the inefficient 802.11 -> 802.3 -> 802.11 conversion that was done before. [Changes since v1] Suggested by Johannes: - Select queue before adding to mpath queue - ieee80211_add_pending_skb -> ieee80211_add_pending_skbs - Remove unnecessary header wme.h Signed-off-by: Javier Cardona Signed-off-by: Andrey Yurovsky Reviewed-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mesh_hwmp.c | 3 ++- net/mac80211/mesh_pathtbl.c | 8 +++----- net/mac80211/rx.c | 17 +++++++++++++++-- net/mac80211/tx.c | 3 --- 4 files changed, 20 insertions(+), 11 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 8e86e910edfc..e93c37ef6a48 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -784,7 +784,6 @@ int mesh_nexthop_lookup(struct sk_buff *skb, mesh_path_add(dst_addr, sdata); mpath = mesh_path_lookup(dst_addr, sdata); if (!mpath) { - dev_kfree_skb(skb); sdata->u.mesh.mshstats.dropped_frames_no_route++; err = -ENOSPC; goto endlookup; @@ -804,6 +803,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb, memcpy(hdr->addr1, mpath->next_hop->sta.addr, ETH_ALEN); } else { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); if (!(mpath->flags & MESH_PATH_RESOLVING)) { /* Start discovery only if it is not running yet */ mesh_queue_preq(mpath, PREQ_Q_F_START); @@ -815,6 +815,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb, skb_unlink(skb_to_free, &mpath->frame_queue); } + info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; skb_queue_tail(&mpath->frame_queue, skb); if (skb_to_free) mesh_path_discard_frame(skb_to_free, sdata); diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index f0304bfdcdff..04b9e4d61b8e 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -499,11 +499,9 @@ enddel: */ void mesh_path_tx_pending(struct mesh_path *mpath) { - struct sk_buff *skb; - - while ((skb = skb_dequeue(&mpath->frame_queue)) && - (mpath->flags & MESH_PATH_ACTIVE)) - dev_queue_xmit(skb); + if (mpath->flags & MESH_PATH_ACTIVE) + ieee80211_add_pending_skbs(mpath->sdata->local, + &mpath->frame_queue); } /** diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 7f33f775c5df..66c797cc85ce 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1479,10 +1479,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) unsigned int hdrlen; struct sk_buff *skb = rx->skb, *fwd_skb; struct ieee80211_local *local = rx->local; + struct ieee80211_sub_if_data *sdata; hdr = (struct ieee80211_hdr *) skb->data; hdrlen = ieee80211_hdrlen(hdr->frame_control); mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen); + sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); if (!ieee80211_is_data(hdr->frame_control)) return RX_CONTINUE; @@ -1492,10 +1494,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) return RX_DROP_MONITOR; if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6){ - struct ieee80211_sub_if_data *sdata; struct mesh_path *mppath; - sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); rcu_read_lock(); mppath = mpp_path_lookup(mesh_hdr->eaddr2, sdata); if (!mppath) { @@ -1541,6 +1541,19 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; fwd_skb->iif = rx->dev->ifindex; ieee80211_select_queue(local, fwd_skb); + if (is_multicast_ether_addr(fwd_hdr->addr3)) + memcpy(fwd_hdr->addr1, fwd_hdr->addr3, + ETH_ALEN); + else { + int err = mesh_nexthop_lookup(fwd_skb, sdata); + /* Failed to immediately resolve next hop: + * fwded frame was dropped or will be added + * later to the pending skb queue. */ + if (err) + return RX_DROP_MONITOR; + } + IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, + fwded_frames); ieee80211_add_pending_skb(local, fwd_skb); } } diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index a204092e8356..2572509d5568 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1419,9 +1419,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, dev_put(sdata->dev); return; } - if (memcmp(sdata->dev->dev_addr, hdr->addr4, ETH_ALEN) != 0) - IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, - fwded_frames); } else if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) { int hdrlen; u16 len_rthdr; -- cgit v1.2.3 From 5061b0c2b9066de426fbc63f1278d2210e789412 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 14 Jul 2009 00:33:34 +0200 Subject: mac80211: cooperate more with network namespaces There are still two places in mac80211 that hardcode the initial net namespace (init_net). One of them is mandated by cfg80211 and will be removed by a separate patch, the other one is used for finding the network device of a pending packet via its ifindex. Remove the latter use by keeping track of the device pointer itself, via the vif pointer, and avoid it going stale by dropping pending frames for a given interface when the interface is removed. To keep track of the vif pointer for the correct interface, change the info->control.vif pointer's internal use to always be the correct vif, and only move it to the vif the driver expects (or NULL for monitor interfaces and injected packets) right before giving the packet to the driver. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/iface.c | 16 ++++++++++- net/mac80211/rx.c | 2 +- net/mac80211/tx.c | 75 +++++++++++++++++++++------------------------------- 3 files changed, 46 insertions(+), 47 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 2f797a86ced5..559d698369c7 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -335,7 +335,10 @@ static int ieee80211_stop(struct net_device *dev) struct ieee80211_local *local = sdata->local; struct ieee80211_if_init_conf conf; struct sta_info *sta; + unsigned long flags; + struct sk_buff *skb, *tmp; u32 hw_reconf_flags = 0; + int i; /* * Stop TX on this interface first. @@ -551,6 +554,18 @@ static int ieee80211_stop(struct net_device *dev) if (hw_reconf_flags) ieee80211_hw_config(local, hw_reconf_flags); + spin_lock_irqsave(&local->queue_stop_reason_lock, flags); + for (i = 0; i < IEEE80211_MAX_QUEUES; i++) { + skb_queue_walk_safe(&local->pending[i], skb, tmp) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + if (info->control.vif == &sdata->vif) { + __skb_unlink(skb, &local->pending[i]); + dev_kfree_skb_irq(skb); + } + } + } + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); + return 0; } @@ -788,7 +803,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); - ndev->features |= NETIF_F_NETNS_LOCAL; /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ sdata = netdev_priv(ndev); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 66c797cc85ce..d9df819eef3b 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1539,7 +1539,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) info = IEEE80211_SKB_CB(fwd_skb); memset(info, 0, sizeof(*info)); info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; - fwd_skb->iif = rx->dev->ifindex; + info->control.vif = &rx->sdata->vif; ieee80211_select_queue(local, fwd_skb); if (is_multicast_ether_addr(fwd_hdr->addr3)) memcpy(fwd_hdr->addr1, fwd_hdr->addr3, diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 2572509d5568..ffd3b10f2696 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -400,6 +400,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) sta_info_set_tim_bit(sta); info->control.jiffies = jiffies; + info->control.vif = &tx->sdata->vif; info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; skb_queue_tail(&sta->ps_tx_buf, tx->skb); return TX_QUEUED; @@ -696,7 +697,7 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) * number, if we have no matching interface then we * neither assign one ourselves nor ask the driver to. */ - if (unlikely(!info->control.vif)) + if (unlikely(info->control.vif->type == NL80211_IFTYPE_MONITOR)) return TX_CONTINUE; if (unlikely(ieee80211_is_ctl(hdr->frame_control))) @@ -1092,6 +1093,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, } else if (*state != HT_AGG_STATE_IDLE) { /* in progress */ queued = true; + info->control.vif = &sdata->vif; info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; __skb_queue_tail(&tid_tx->pending, skb); } @@ -1143,6 +1145,7 @@ static int __ieee80211_tx(struct ieee80211_local *local, { struct sk_buff *skb = *skbp, *next; struct ieee80211_tx_info *info; + struct ieee80211_sub_if_data *sdata; unsigned long flags; int ret, len; bool fragm = false; @@ -1167,7 +1170,24 @@ static int __ieee80211_tx(struct ieee80211_local *local, next = skb->next; len = skb->len; + + sdata = vif_to_sdata(info->control.vif); + + switch (sdata->vif.type) { + case NL80211_IFTYPE_MONITOR: + info->control.vif = NULL; + break; + case NL80211_IFTYPE_AP_VLAN: + info->control.vif = &container_of(sdata->bss, + struct ieee80211_sub_if_data, u.ap)->vif; + break; + default: + /* keep */ + break; + } + ret = drv_tx(local, skb); + info->control.vif = &sdata->vif; if (WARN_ON(ret != NETDEV_TX_OK && skb->len != len)) { dev_kfree_skb(skb); ret = NETDEV_TX_OK; @@ -1386,11 +1406,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct ieee80211_sub_if_data *tmp_sdata; int headroom; bool may_encrypt; - enum { - NOT_MONITOR, - FOUND_SDATA, - UNKNOWN_ADDRESS, - } monitor_iface = NOT_MONITOR; dev_hold(sdata->dev); @@ -1424,7 +1439,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, u16 len_rthdr; info->flags |= IEEE80211_TX_CTL_INJECTED; - monitor_iface = UNKNOWN_ADDRESS; len_rthdr = ieee80211_get_radiotap_len(skb->data); hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr); @@ -1454,7 +1468,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, dev_hold(tmp_sdata->dev); dev_put(sdata->dev); sdata = tmp_sdata; - monitor_iface = FOUND_SDATA; break; } } @@ -1476,13 +1489,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, return; } - tmp_sdata = sdata; - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - tmp_sdata = container_of(sdata->bss, - struct ieee80211_sub_if_data, - u.ap); - if (likely(monitor_iface != UNKNOWN_ADDRESS)) - info->control.vif = &tmp_sdata->vif; + info->control.vif = &sdata->vif; ieee80211_select_queue(local, skb); ieee80211_tx(sdata, skb, false); @@ -1534,9 +1541,6 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb, if (unlikely(skb->len < len_rthdr)) goto fail; /* skb too short for claimed rt header extent */ - /* needed because we set skb device to master */ - skb->iif = dev->ifindex; - /* * fix up the pointers accounting for the radiotap * header still being in there. We are being given @@ -1810,8 +1814,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, nh_pos += hdrlen; h_pos += hdrlen; - skb->iif = dev->ifindex; - dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; @@ -1856,32 +1858,13 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata; struct sta_info *sta; struct ieee80211_hdr *hdr; - struct net_device *dev; int ret; bool result = true; - /* does interface still exist? */ - dev = dev_get_by_index(&init_net, skb->iif); - if (!dev) { - dev_kfree_skb(skb); - return true; - } - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - sdata = container_of(sdata->bss, - struct ieee80211_sub_if_data, - u.ap); - - if (unlikely(info->control.vif && info->control.vif != &sdata->vif)) { - dev_kfree_skb(skb); - result = true; - goto out; - } + sdata = vif_to_sdata(info->control.vif); if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) { - /* do not use sdata, it may have been changed above */ - ieee80211_tx(IEEE80211_DEV_TO_SUB_IF(dev), skb, true); + ieee80211_tx(sdata, skb, true); } else { hdr = (struct ieee80211_hdr *)skb->data; sta = sta_info_get(local, hdr->addr1); @@ -1891,9 +1874,6 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, result = false; } - out: - dev_put(dev); - return result; } @@ -1921,10 +1901,16 @@ void ieee80211_tx_pending(unsigned long data) while (!skb_queue_empty(&local->pending[i])) { struct sk_buff *skb = __skb_dequeue(&local->pending[i]); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_sub_if_data *sdata; + + sdata = vif_to_sdata(info->control.vif); + dev_hold(sdata->dev); spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); txok = ieee80211_tx_pending_skb(local, skb); + dev_put(sdata->dev); if (!txok) __skb_queue_head(&local->pending[i], skb); spin_lock_irqsave(&local->queue_stop_reason_lock, @@ -2234,7 +2220,6 @@ void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, skb_set_network_header(skb, 0); skb_set_transport_header(skb, 0); - skb->iif = sdata->dev->ifindex; if (!encrypt) info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; -- cgit v1.2.3 From 463d018323851a608eef52a9427b0585005c647f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 14 Jul 2009 00:33:35 +0200 Subject: cfg80211: make aware of net namespaces In order to make cfg80211/nl80211 aware of network namespaces, we have to do the following things: * del_virtual_intf method takes an interface index rather than a netdev pointer - simply change this * nl80211 uses init_net a lot, it changes to use the sender's network namespace * scan requests use the interface index, hold a netdev pointer and reference instead * we want a wiphy and its associated virtual interfaces to be in one netns together, so - we need to be able to change ns for a given interface, so export dev_change_net_namespace() - for each virtual interface set the NETIF_F_NETNS_LOCAL flag, and clear that flag only when the wiphy changes ns, to disallow breaking this invariant * when a network namespace goes away, we need to reparent the wiphy to init_net * cfg80211 users that support creating virtual interfaces must create them in the wiphy's namespace, currently this affects only mac80211 The end result is that you can now switch an entire wiphy into a different network namespace with the new command iw phy# set netns and all virtual interfaces will follow (or the operation fails). Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 52928ad90570..4bbf5007799b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -57,19 +57,9 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name, return 0; } -static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) +static int ieee80211_del_iface(struct wiphy *wiphy, struct net_device *dev) { - struct net_device *dev; - struct ieee80211_sub_if_data *sdata; - - /* we're under RTNL */ - dev = __dev_get_by_index(&init_net, ifindex); - if (!dev) - return -ENODEV; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - ieee80211_if_remove(sdata); + ieee80211_if_remove(IEEE80211_DEV_TO_SUB_IF(dev)); return 0; } -- cgit v1.2.3 From a272a720660059c30fa038113b77fa2a096437d9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 14 Jul 2009 00:33:36 +0200 Subject: mac80211: allow using network namespaces This finally opens up the ability to put mac80211 devices into different network namespaces. As long as you don't have sysfs, that is. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/iface.c | 1 + net/mac80211/main.c | 1 + 2 files changed, 2 insertions(+) (limited to 'net/mac80211') diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 559d698369c7..0cb29df09e35 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -787,6 +787,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, name, ieee80211_if_setup); if (!ndev) return -ENOMEM; + dev_net_set(ndev, wiphy_net(local->hw.wiphy)); ndev->needed_headroom = local->tx_headroom + 4*6 /* four MAC addresses */ diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 3234f3751d22..02cabbffc19a 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -620,6 +620,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, if (!wiphy) return NULL; + wiphy->netnsok = true; wiphy->privid = mac80211_wiphy_privid; /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */ -- cgit v1.2.3 From 7d3be3cc489176bc7bd23e673b0b4aef597af2b3 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Thu, 23 Jul 2009 12:13:41 +0200 Subject: mac80211: refactor the scan code Move the processing of each scan state into its own functions for better readability. This patch does not introduce functional changes. Signed-off-by: Helmut Schaa Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/scan.c | 136 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 78 insertions(+), 58 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 74820656dc89..71500f1dddbc 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -474,13 +474,87 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, return rc; } +static int ieee80211_scan_state_set_channel(struct ieee80211_local *local, + unsigned long *next_delay) +{ + int skip; + struct ieee80211_channel *chan; + struct ieee80211_sub_if_data *sdata = local->scan_sdata; + + /* if no more bands/channels left, complete scan */ + if (local->scan_channel_idx >= local->scan_req->n_channels) { + ieee80211_scan_completed(&local->hw, false); + return 1; + } + skip = 0; + chan = local->scan_req->channels[local->scan_channel_idx]; + + if (chan->flags & IEEE80211_CHAN_DISABLED || + (sdata->vif.type == NL80211_IFTYPE_ADHOC && + chan->flags & IEEE80211_CHAN_NO_IBSS)) + skip = 1; + + if (!skip) { + local->scan_channel = chan; + if (ieee80211_hw_config(local, + IEEE80211_CONF_CHANGE_CHANNEL)) + skip = 1; + } + + /* advance state machine to next channel/band */ + local->scan_channel_idx++; + + if (skip) + return 0; + + /* + * Probe delay is used to update the NAV, cf. 11.1.3.2.2 + * (which unfortunately doesn't say _why_ step a) is done, + * but it waits for the probe delay or until a frame is + * received - and the received frame would update the NAV). + * For now, we do not support waiting until a frame is + * received. + * + * In any case, it is not necessary for a passive scan. + */ + if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN || + !local->scan_req->n_ssids) { + *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; + return 0; + } + + *next_delay = IEEE80211_PROBE_DELAY; + local->scan_state = SCAN_SEND_PROBE; + + return 0; +} + +static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, + unsigned long *next_delay) +{ + int i; + struct ieee80211_sub_if_data *sdata = local->scan_sdata; + + for (i = 0; i < local->scan_req->n_ssids; i++) + ieee80211_send_probe_req( + sdata, NULL, + local->scan_req->ssids[i].ssid, + local->scan_req->ssids[i].ssid_len, + local->scan_req->ie, local->scan_req->ie_len); + + /* + * After sending probe requests, wait for probe responses + * on the channel. + */ + *next_delay = IEEE80211_CHANNEL_TIME; + local->scan_state = SCAN_SET_CHANNEL; +} + void ieee80211_scan_work(struct work_struct *work) { struct ieee80211_local *local = container_of(work, struct ieee80211_local, scan_work.work); struct ieee80211_sub_if_data *sdata = local->scan_sdata; - struct ieee80211_channel *chan; - int skip, i; unsigned long next_delay = 0; mutex_lock(&local->scan_mtx); @@ -515,65 +589,11 @@ void ieee80211_scan_work(struct work_struct *work) switch (local->scan_state) { case SCAN_SET_CHANNEL: - /* if no more bands/channels left, complete scan */ - if (local->scan_channel_idx >= local->scan_req->n_channels) { - ieee80211_scan_completed(&local->hw, false); + if (ieee80211_scan_state_set_channel(local, &next_delay)) return; - } - skip = 0; - chan = local->scan_req->channels[local->scan_channel_idx]; - - if (chan->flags & IEEE80211_CHAN_DISABLED || - (sdata->vif.type == NL80211_IFTYPE_ADHOC && - chan->flags & IEEE80211_CHAN_NO_IBSS)) - skip = 1; - - if (!skip) { - local->scan_channel = chan; - if (ieee80211_hw_config(local, - IEEE80211_CONF_CHANGE_CHANNEL)) - skip = 1; - } - - /* advance state machine to next channel/band */ - local->scan_channel_idx++; - - if (skip) - break; - - /* - * Probe delay is used to update the NAV, cf. 11.1.3.2.2 - * (which unfortunately doesn't say _why_ step a) is done, - * but it waits for the probe delay or until a frame is - * received - and the received frame would update the NAV). - * For now, we do not support waiting until a frame is - * received. - * - * In any case, it is not necessary for a passive scan. - */ - if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN || - !local->scan_req->n_ssids) { - next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; - break; - } - - next_delay = IEEE80211_PROBE_DELAY; - local->scan_state = SCAN_SEND_PROBE; break; case SCAN_SEND_PROBE: - for (i = 0; i < local->scan_req->n_ssids; i++) - ieee80211_send_probe_req( - sdata, NULL, - local->scan_req->ssids[i].ssid, - local->scan_req->ssids[i].ssid_len, - local->scan_req->ie, local->scan_req->ie_len); - - /* - * After sending probe requests, wait for probe responses - * on the channel. - */ - next_delay = IEEE80211_CHANNEL_TIME; - local->scan_state = SCAN_SET_CHANNEL; + ieee80211_scan_state_send_probe(local, &next_delay); break; } -- cgit v1.2.3 From f502d09b750437a4ec9c63333acf1070fe7958af Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Thu, 23 Jul 2009 12:13:48 +0200 Subject: mac80211: advance the state machine immediately if no delay is needed Instead of queueing the scan work again without delay just process the next state immediately. Signed-off-by: Helmut Schaa Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/scan.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 71500f1dddbc..db122e4e60e5 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -587,15 +587,21 @@ void ieee80211_scan_work(struct work_struct *work) return; } - switch (local->scan_state) { - case SCAN_SET_CHANNEL: - if (ieee80211_scan_state_set_channel(local, &next_delay)) - return; - break; - case SCAN_SEND_PROBE: - ieee80211_scan_state_send_probe(local, &next_delay); - break; - } + /* + * as long as no delay is required advance immediately + * without scheduling a new work + */ + do { + switch (local->scan_state) { + case SCAN_SET_CHANNEL: + if (ieee80211_scan_state_set_channel(local, &next_delay)) + return; + break; + case SCAN_SEND_PROBE: + ieee80211_scan_state_send_probe(local, &next_delay); + break; + } + } while (next_delay == 0); queue_delayed_work(local->hw.workqueue, &local->scan_work, next_delay); -- cgit v1.2.3 From 2fb3f028a9a46bd344329766257699b4acb36525 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Thu, 23 Jul 2009 12:13:56 +0200 Subject: mac80211: introduce a new scan state "decision" Introduce a new scan state "decision" which is entered after every completed scan operation and decides about the next steps. At first the decision is in any case to scan the next channel. This shouldn't introduce any functional changes. Signed-off-by: Helmut Schaa Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/scan.c | 40 ++++++++++++++++++++++++++-------------- 2 files changed, 27 insertions(+), 15 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 6a0177137dd5..4166418b4aa7 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -678,7 +678,7 @@ struct ieee80211_local { int scan_channel_idx; int scan_ies_len; - enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state; + enum { SCAN_DECISION, SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state; struct delayed_work scan_work; struct ieee80211_sub_if_data *scan_sdata; enum nl80211_channel_type oper_channel_type; diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index db122e4e60e5..48f910ae95c0 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -376,7 +376,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) } mutex_unlock(&local->iflist_mtx); - local->scan_state = SCAN_SET_CHANNEL; + local->scan_state = SCAN_DECISION; local->scan_channel_idx = 0; spin_lock_bh(&local->filter_lock); @@ -474,18 +474,27 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, return rc; } -static int ieee80211_scan_state_set_channel(struct ieee80211_local *local, - unsigned long *next_delay) +static int ieee80211_scan_state_decision(struct ieee80211_local *local, + unsigned long *next_delay) { - int skip; - struct ieee80211_channel *chan; - struct ieee80211_sub_if_data *sdata = local->scan_sdata; - /* if no more bands/channels left, complete scan */ if (local->scan_channel_idx >= local->scan_req->n_channels) { ieee80211_scan_completed(&local->hw, false); return 1; } + + *next_delay = 0; + local->scan_state = SCAN_SET_CHANNEL; + return 0; +} + +static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, + unsigned long *next_delay) +{ + int skip; + struct ieee80211_channel *chan; + struct ieee80211_sub_if_data *sdata = local->scan_sdata; + skip = 0; chan = local->scan_req->channels[local->scan_channel_idx]; @@ -505,7 +514,7 @@ static int ieee80211_scan_state_set_channel(struct ieee80211_local *local, local->scan_channel_idx++; if (skip) - return 0; + return; /* * Probe delay is used to update the NAV, cf. 11.1.3.2.2 @@ -520,13 +529,13 @@ static int ieee80211_scan_state_set_channel(struct ieee80211_local *local, if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN || !local->scan_req->n_ssids) { *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; - return 0; + local->scan_state = SCAN_DECISION; + return; } + /* active scan, send probes */ *next_delay = IEEE80211_PROBE_DELAY; local->scan_state = SCAN_SEND_PROBE; - - return 0; } static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, @@ -547,7 +556,7 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, * on the channel. */ *next_delay = IEEE80211_CHANNEL_TIME; - local->scan_state = SCAN_SET_CHANNEL; + local->scan_state = SCAN_DECISION; } void ieee80211_scan_work(struct work_struct *work) @@ -593,10 +602,13 @@ void ieee80211_scan_work(struct work_struct *work) */ do { switch (local->scan_state) { - case SCAN_SET_CHANNEL: - if (ieee80211_scan_state_set_channel(local, &next_delay)) + case SCAN_DECISION: + if (ieee80211_scan_state_decision(local, &next_delay)) return; break; + case SCAN_SET_CHANNEL: + ieee80211_scan_state_set_channel(local, &next_delay); + break; case SCAN_SEND_PROBE: ieee80211_scan_state_send_probe(local, &next_delay); break; -- cgit v1.2.3 From fbe9c429f195111bbf7f1630efa19aee295fd8e7 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Thu, 23 Jul 2009 12:14:04 +0200 Subject: mac80211: Replace {sw, hw}_scanning variables with a bitfield Use a bitfield to store the current scan mode instead of two boolean variables {sw,hw}_scanning. This patch does not introduce functional changes but allows us to enhance the scan flags later (for example for background scanning). Signed-off-by: Helmut Schaa Signed-off-by: John W. Linville --- net/mac80211/ibss.c | 2 +- net/mac80211/ieee80211_i.h | 7 ++++++- net/mac80211/iface.c | 4 ++-- net/mac80211/main.c | 2 +- net/mac80211/mesh.c | 2 +- net/mac80211/mlme.c | 8 ++++---- net/mac80211/rx.c | 6 +++--- net/mac80211/scan.c | 23 ++++++++++------------- net/mac80211/tx.c | 6 +++--- 9 files changed, 31 insertions(+), 29 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 8e2220000e5c..6e3cca65c460 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -742,7 +742,7 @@ static void ieee80211_ibss_work(struct work_struct *work) if (!netif_running(sdata->dev)) return; - if (local->sw_scanning || local->hw_scanning) + if (local->scanning) return; if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_ADHOC)) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 4166418b4aa7..783a125402b0 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -570,6 +570,11 @@ enum queue_stop_reason { IEEE80211_QUEUE_STOP_REASON_SKB_ADD, }; +enum { + SCAN_SW_SCANNING, + SCAN_HW_SCANNING +}; + struct ieee80211_local { /* embed the driver visible part. * don't cast (use the static inlines below), but we keep @@ -668,7 +673,7 @@ struct ieee80211_local { /* Scanning and BSS list */ struct mutex scan_mtx; - bool sw_scanning, hw_scanning; + unsigned long scanning; struct cfg80211_ssid scan_ssid; struct cfg80211_scan_request int_scan_req; struct cfg80211_scan_request *scan_req; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 0cb29df09e35..d79a21105042 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -518,7 +518,7 @@ static int ieee80211_stop(struct net_device *dev) * the scan_sdata is NULL already don't send out a * scan event to userspace -- the scan is incomplete. */ - if (local->sw_scanning) + if (test_bit(SCAN_SW_SCANNING, &local->scanning)) ieee80211_scan_completed(&local->hw, true); } @@ -920,7 +920,7 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) struct ieee80211_sub_if_data *sdata; int count = 0; - if (local->hw_scanning || local->sw_scanning) + if (local->scanning) return ieee80211_idle_off(local, "scanning"); list_for_each_entry(sdata, &local->interfaces, list) { diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 02cabbffc19a..c1a799194fff 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -198,7 +198,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, } if (changed & BSS_CHANGED_BEACON_ENABLED) { - if (local->sw_scanning) { + if (test_bit(SCAN_SW_SCANNING, &local->scanning)) { sdata->vif.bss_conf.enable_beacon = false; } else { /* diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 8a97b1423088..9a3826978b1c 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -597,7 +597,7 @@ static void ieee80211_mesh_work(struct work_struct *work) if (!netif_running(sdata->dev)) return; - if (local->sw_scanning || local->hw_scanning) + if (local->scanning) return; while ((skb = skb_dequeue(&ifmsh->skb_queue))) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 523c0d994d15..52b6f8327a5b 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -581,7 +581,7 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, if (!ifmgd->associated) return; - if (sdata->local->sw_scanning || sdata->local->hw_scanning) + if (sdata->local->scanning) return; /* Disregard subsequent beacons if we are already running a timer @@ -639,7 +639,7 @@ static void ieee80211_enable_ps(struct ieee80211_local *local, * If we are scanning right now then the parameters will * take effect when scan finishes. */ - if (local->hw_scanning || local->sw_scanning) + if (local->scanning) return; if (conf->dynamic_ps_timeout > 0 && @@ -2038,7 +2038,7 @@ static void ieee80211_sta_work(struct work_struct *work) if (!netif_running(sdata->dev)) return; - if (local->sw_scanning || local->hw_scanning) + if (local->scanning) return; if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) @@ -2213,7 +2213,7 @@ static void ieee80211_sta_monitor_work(struct work_struct *work) container_of(work, struct ieee80211_sub_if_data, u.mgd.monitor_work); - if (sdata->local->sw_scanning || sdata->local->hw_scanning) + if (sdata->local->scanning) return; ieee80211_mgd_probe_ap(sdata, false); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index d9df819eef3b..9c1679d124ba 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -418,10 +418,10 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx) struct ieee80211_local *local = rx->local; struct sk_buff *skb = rx->skb; - if (unlikely(local->hw_scanning)) + if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning))) return ieee80211_scan_rx(rx->sdata, skb); - if (unlikely(local->sw_scanning)) { + if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning))) { /* drop all the other packets during a software scan anyway */ if (ieee80211_scan_rx(rx->sdata, skb) != RX_QUEUED) dev_kfree_skb(skb); @@ -2136,7 +2136,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, return; } - if (unlikely(local->sw_scanning || local->hw_scanning)) + if (unlikely(local->scanning)) rx.flags |= IEEE80211_RX_IN_SCAN; ieee80211_parse_qos(&rx); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 48f910ae95c0..4233c3d700ce 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -265,7 +265,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) mutex_lock(&local->scan_mtx); - if (WARN_ON(!local->hw_scanning && !local->sw_scanning)) { + if (WARN_ON(!local->scanning)) { mutex_unlock(&local->scan_mtx); return; } @@ -275,16 +275,15 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) return; } - if (local->hw_scanning) + if (test_bit(SCAN_HW_SCANNING, &local->scanning)) ieee80211_restore_scan_ies(local); if (local->scan_req != &local->int_scan_req) cfg80211_scan_done(local->scan_req, aborted); local->scan_req = NULL; - was_hw_scan = local->hw_scanning; - local->hw_scanning = false; - local->sw_scanning = false; + was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning); + local->scanning = 0; local->scan_channel = NULL; /* we only have to protect scan_req and hw/sw scan */ @@ -434,9 +433,9 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, } if (local->ops->hw_scan) - local->hw_scanning = true; + __set_bit(SCAN_HW_SCANNING, &local->scanning); else - local->sw_scanning = true; + __set_bit(SCAN_SW_SCANNING, &local->scanning); /* * Kicking off the scan need not be protected, * only the scan variable stuff, since now @@ -459,11 +458,9 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, mutex_lock(&local->scan_mtx); if (rc) { - if (local->ops->hw_scan) { - local->hw_scanning = false; + if (local->ops->hw_scan) ieee80211_restore_scan_ies(local); - } else - local->sw_scanning = false; + local->scanning = 0; ieee80211_recalc_idle(local); @@ -572,7 +569,7 @@ void ieee80211_scan_work(struct work_struct *work) return; } - if (local->scan_req && !(local->sw_scanning || local->hw_scanning)) { + if (local->scan_req && !local->scanning) { struct cfg80211_scan_request *req = local->scan_req; int rc; @@ -663,7 +660,7 @@ void ieee80211_scan_cancel(struct ieee80211_local *local) * queued -- mostly at suspend under RTNL. */ mutex_lock(&local->scan_mtx); - swscan = local->sw_scanning; + swscan = test_bit(SCAN_SW_SCANNING, &local->scanning); mutex_unlock(&local->scan_mtx); if (swscan) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index ffd3b10f2696..d7491dc2a65c 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -192,7 +192,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) return TX_CONTINUE; - if (unlikely(tx->local->sw_scanning) && + if (unlikely(test_bit(SCAN_SW_SCANNING, &tx->local->scanning)) && !ieee80211_is_probe_req(hdr->frame_control) && !ieee80211_is_nullfunc(hdr->frame_control)) /* @@ -552,7 +552,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) * Lets not bother rate control if we're associated and cannot * talk to the sta. This should not happen. */ - if (WARN((tx->local->sw_scanning) && + if (WARN(test_bit(SCAN_SW_SCANNING, &tx->local->scanning) && (sta_flags & WLAN_STA_ASSOC) && !rate_usable_index_exists(sband, &tx->sta->sta), "%s: Dropped data frame as no usable bitrate found while " @@ -1411,7 +1411,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && local->hw.conf.dynamic_ps_timeout > 0 && - !local->sw_scanning && !local->hw_scanning && local->ps_sdata) { + !(local->scanning) && local->ps_sdata) { if (local->hw.conf.flags & IEEE80211_CONF_PS) { ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_QUEUE_STOP_REASON_PS); -- cgit v1.2.3 From 142b9f5074dc0d09dc0025739ad437723d7bf527 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Thu, 23 Jul 2009 13:18:01 +0200 Subject: mac80211: implement basic background scanning Introduce a new scan flag "SCAN_OFF_CHANNEL" which basically tells us that we are currently on a different channel for scanning and cannot RX/TX. "SCAN_SW_SCANNING" tells us that we are currently running a software scan but we might as well be on the operating channel to RX/TX. While "SCAN_SW_SCANNING" is set during the whole scan "SCAN_OFF_CHANNEL" is set when leaving the operating channel and unset when coming back. Introduce two new scan states "SCAN_LEAVE_OPER_CHANNEL" and "SCAN_ENTER_OPER_CHANNEL" which basically implement the functionality we need to leave the operating channel (send a nullfunc to the AP and stop the queues) and enter it again (send a nullfunc to the AP and start the queues again). Enhance the scan state "SCAN_DECISION" to switch back to the operating channel after each scanned channel. In the future it sould be simple to enhance the decision state to scan as much channels in a row as the qos latency allows us. Signed-off-by: Helmut Schaa Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 36 +++++++++++++- net/mac80211/rx.c | 6 ++- net/mac80211/scan.c | 117 +++++++++++++++++++++++++++++++++++++++++---- net/mac80211/tx.c | 2 +- 4 files changed, 148 insertions(+), 13 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 783a125402b0..efda19ee0152 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -570,9 +570,41 @@ enum queue_stop_reason { IEEE80211_QUEUE_STOP_REASON_SKB_ADD, }; +/** + * mac80211 scan flags - currently active scan mode + * + * @SCAN_SW_SCANNING: We're currently in the process of scanning but may as + * well be on the operating channel + * @SCAN_HW_SCANNING: The hardware is scanning for us, we have no way to + * determine if we are on the operating channel or not + * @SCAN_OFF_CHANNEL: We're off our operating channel for scanning, + * gets only set in conjunction with SCAN_SW_SCANNING + */ enum { SCAN_SW_SCANNING, - SCAN_HW_SCANNING + SCAN_HW_SCANNING, + SCAN_OFF_CHANNEL, +}; + +/** + * enum mac80211_scan_state - scan state machine states + * + * @SCAN_DECISION: Main entry point to the scan state machine, this state + * determines if we should keep on scanning or switch back to the + * operating channel + * @SCAN_SET_CHANNEL: Set the next channel to be scanned + * @SCAN_SEND_PROBE: Send probe requests and wait for probe responses + * @SCAN_LEAVE_OPER_CHANNEL: Leave the operating channel, notify the AP + * about us leaving the channel and stop all associated STA interfaces + * @SCAN_ENTER_OPER_CHANNEL: Enter the operating channel again, notify the + * AP about us being back and restart all associated STA interfaces + */ +enum mac80211_scan_state { + SCAN_DECISION, + SCAN_SET_CHANNEL, + SCAN_SEND_PROBE, + SCAN_LEAVE_OPER_CHANNEL, + SCAN_ENTER_OPER_CHANNEL, }; struct ieee80211_local { @@ -683,7 +715,7 @@ struct ieee80211_local { int scan_channel_idx; int scan_ies_len; - enum { SCAN_DECISION, SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state; + enum mac80211_scan_state scan_state; struct delayed_work scan_work; struct ieee80211_sub_if_data *scan_sdata; enum nl80211_channel_type oper_channel_type; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 9c1679d124ba..cb95a3116034 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -421,7 +421,8 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx) if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning))) return ieee80211_scan_rx(rx->sdata, skb); - if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning))) { + if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning) && + (rx->flags & IEEE80211_RX_IN_SCAN))) { /* drop all the other packets during a software scan anyway */ if (ieee80211_scan_rx(rx->sdata, skb) != RX_QUEUED) dev_kfree_skb(skb); @@ -2136,7 +2137,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, return; } - if (unlikely(local->scanning)) + if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) || + test_bit(SCAN_OFF_CHANNEL, &local->scanning))) rx.flags |= IEEE80211_RX_IN_SCAN; ieee80211_parse_qos(&rx); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 4233c3d700ce..d56b9da8b28a 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -365,12 +365,11 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) ieee80211_bss_info_change_notify( sdata, BSS_CHANGED_BEACON_ENABLED); - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - if (sdata->u.mgd.associated) { - netif_tx_stop_all_queues(sdata->dev); - ieee80211_scan_ps_enable(sdata); - } - } else + /* + * only handle non-STA interfaces here, STA interfaces + * are handled in the scan state machine + */ + if (sdata->vif.type != NL80211_IFTYPE_STATION) netif_tx_stop_all_queues(sdata->dev); } mutex_unlock(&local->iflist_mtx); @@ -474,17 +473,113 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, static int ieee80211_scan_state_decision(struct ieee80211_local *local, unsigned long *next_delay) { - /* if no more bands/channels left, complete scan */ + bool associated = false; + struct ieee80211_sub_if_data *sdata; + + /* if no more bands/channels left, complete scan and advance to the idle state */ if (local->scan_channel_idx >= local->scan_req->n_channels) { ieee80211_scan_completed(&local->hw, false); return 1; } + /* check if at least one STA interface is associated */ + mutex_lock(&local->iflist_mtx); + list_for_each_entry(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; + + if (sdata->vif.type == NL80211_IFTYPE_STATION) { + if (sdata->u.mgd.associated) { + associated = true; + break; + } + } + } + mutex_unlock(&local->iflist_mtx); + + if (local->scan_channel) { + /* + * we're currently scanning a different channel, let's + * switch back to the operating channel now if at least + * one interface is associated. Otherwise just scan the + * next channel + */ + if (associated) + local->scan_state = SCAN_ENTER_OPER_CHANNEL; + else + local->scan_state = SCAN_SET_CHANNEL; + } else { + /* + * we're on the operating channel currently, let's + * leave that channel now to scan another one + */ + local->scan_state = SCAN_LEAVE_OPER_CHANNEL; + } + *next_delay = 0; - local->scan_state = SCAN_SET_CHANNEL; return 0; } +static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local, + unsigned long *next_delay) +{ + struct ieee80211_sub_if_data *sdata; + + /* + * notify the AP about us leaving the channel and stop all STA interfaces + */ + mutex_lock(&local->iflist_mtx); + list_for_each_entry(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; + + if (sdata->vif.type == NL80211_IFTYPE_STATION) { + netif_tx_stop_all_queues(sdata->dev); + if (sdata->u.mgd.associated) + ieee80211_scan_ps_enable(sdata); + } + } + mutex_unlock(&local->iflist_mtx); + + __set_bit(SCAN_OFF_CHANNEL, &local->scanning); + + /* advance to the next channel to be scanned */ + *next_delay = HZ / 10; + local->scan_state = SCAN_SET_CHANNEL; +} + +static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *local, + unsigned long *next_delay) +{ + struct ieee80211_sub_if_data *sdata = local->scan_sdata; + + /* switch back to the operating channel */ + local->scan_channel = NULL; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); + + /* + * notify the AP about us being back and restart all STA interfaces + */ + mutex_lock(&local->iflist_mtx); + list_for_each_entry(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; + + /* Tell AP we're back */ + if (sdata->vif.type == NL80211_IFTYPE_STATION) { + if (sdata->u.mgd.associated) + ieee80211_scan_ps_disable(sdata); + netif_tx_wake_all_queues(sdata->dev); + } + } + mutex_unlock(&local->iflist_mtx); + + __clear_bit(SCAN_OFF_CHANNEL, &local->scanning); + + *next_delay = HZ / 5; + local->scan_state = SCAN_DECISION; +} + static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, unsigned long *next_delay) { @@ -609,6 +704,12 @@ void ieee80211_scan_work(struct work_struct *work) case SCAN_SEND_PROBE: ieee80211_scan_state_send_probe(local, &next_delay); break; + case SCAN_LEAVE_OPER_CHANNEL: + ieee80211_scan_state_leave_oper_channel(local, &next_delay); + break; + case SCAN_ENTER_OPER_CHANNEL: + ieee80211_scan_state_enter_oper_channel(local, &next_delay); + break; } } while (next_delay == 0); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index d7491dc2a65c..70ff4f065665 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -192,7 +192,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) return TX_CONTINUE; - if (unlikely(test_bit(SCAN_SW_SCANNING, &tx->local->scanning)) && + if (unlikely(test_bit(SCAN_OFF_CHANNEL, &tx->local->scanning)) && !ieee80211_is_probe_req(hdr->frame_control) && !ieee80211_is_nullfunc(hdr->frame_control)) /* -- cgit v1.2.3 From 977923b00c79185c11b4b47664f5ffa4c3820438 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Thu, 23 Jul 2009 12:14:20 +0200 Subject: mac80211: rename scan_state to next_scan_state Rename scan_state to next_scan_state to better reflect what it is used for. Signed-off-by: Helmut Schaa Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/scan.c | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index efda19ee0152..c6b25cb73284 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -715,7 +715,7 @@ struct ieee80211_local { int scan_channel_idx; int scan_ies_len; - enum mac80211_scan_state scan_state; + enum mac80211_scan_state next_scan_state; struct delayed_work scan_work; struct ieee80211_sub_if_data *scan_sdata; enum nl80211_channel_type oper_channel_type; diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index d56b9da8b28a..b376775e722f 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -374,7 +374,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) } mutex_unlock(&local->iflist_mtx); - local->scan_state = SCAN_DECISION; + local->next_scan_state = SCAN_DECISION; local->scan_channel_idx = 0; spin_lock_bh(&local->filter_lock); @@ -505,15 +505,15 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local, * next channel */ if (associated) - local->scan_state = SCAN_ENTER_OPER_CHANNEL; + local->next_scan_state = SCAN_ENTER_OPER_CHANNEL; else - local->scan_state = SCAN_SET_CHANNEL; + local->next_scan_state = SCAN_SET_CHANNEL; } else { /* * we're on the operating channel currently, let's * leave that channel now to scan another one */ - local->scan_state = SCAN_LEAVE_OPER_CHANNEL; + local->next_scan_state = SCAN_LEAVE_OPER_CHANNEL; } *next_delay = 0; @@ -545,7 +545,7 @@ static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *loca /* advance to the next channel to be scanned */ *next_delay = HZ / 10; - local->scan_state = SCAN_SET_CHANNEL; + local->next_scan_state = SCAN_SET_CHANNEL; } static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *local, @@ -577,7 +577,7 @@ static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *loca __clear_bit(SCAN_OFF_CHANNEL, &local->scanning); *next_delay = HZ / 5; - local->scan_state = SCAN_DECISION; + local->next_scan_state = SCAN_DECISION; } static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, @@ -621,13 +621,13 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN || !local->scan_req->n_ssids) { *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; - local->scan_state = SCAN_DECISION; + local->next_scan_state = SCAN_DECISION; return; } /* active scan, send probes */ *next_delay = IEEE80211_PROBE_DELAY; - local->scan_state = SCAN_SEND_PROBE; + local->next_scan_state = SCAN_SEND_PROBE; } static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, @@ -648,7 +648,7 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, * on the channel. */ *next_delay = IEEE80211_CHANNEL_TIME; - local->scan_state = SCAN_DECISION; + local->next_scan_state = SCAN_DECISION; } void ieee80211_scan_work(struct work_struct *work) @@ -693,7 +693,7 @@ void ieee80211_scan_work(struct work_struct *work) * without scheduling a new work */ do { - switch (local->scan_state) { + switch (local->next_scan_state) { case SCAN_DECISION: if (ieee80211_scan_state_decision(local, &next_delay)) return; -- cgit v1.2.3 From 485318471e85c1ddb5e3056fa30fdbbc46d759c6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 23 Jul 2009 16:50:16 +0200 Subject: mac80211: fix mlme timeouts When a new MLME work is created, its timeout is initialised to 0. This is wrong, it could then be thought of as having an actual timeout in the future (time_is_after_jiffies() can return true). Instead, it should be initialised to jiffies so that it will run right away as soon as the mlme work is executed. Signed-off-by: Johannes Berg Reported-by: Luciano Roth Coelho Reported-by: Alban Browaeys Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net/mac80211') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 52b6f8327a5b..807ab89bdad9 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2377,6 +2377,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, wk->state = IEEE80211_MGD_STATE_PROBE; wk->auth_alg = auth_alg; + wk->timeout = jiffies; /* run right away */ /* * XXX: if still associated need to tell AP that we're going @@ -2448,6 +2449,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, wk->state = IEEE80211_MGD_STATE_ASSOC; wk->tries = 0; + wk->timeout = jiffies; /* run right away */ if (req->use_mfp) { ifmgd->mfp = IEEE80211_MFP_REQUIRED; -- cgit v1.2.3 From 91a3bd76155085d41520cf41ede39e8b7f01aeff Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 23 Jul 2009 16:37:47 -0700 Subject: mac80211: fix MLME issuing of probe requests while scanning We were issuing probe requests to the associated AP on the wrong band by having our beacon timer loss trigger while we are scanning. When we would scan the timer could hit and force us to send a probe request to the AP but with a chance we'd be on the wrong band. This leads to finding no usable bitrate but we should not get so far on the xmit path. We should not be trying to send these probe request frames so prevent ieee80211_mgd_probe_ap() from sending these. As it turns out all callers of ieee80211_mgd_probe_ap() need this check so we just move the scan check there. This means we can remove the recenlty added check during ieee80211_sta_monitor_work(). Additionally we now fix a race condition added by the patch "mac80211: do not monitor the connection while scanning" which had the same check in ieee80211_sta_conn_mon_timer(). The race happens because the timer routine *does* a valid check for scanning but after it queues work into the mac80211 workqueue the work callback can kick off with scanning enabled and cause the same issue we were trying to avoid. The more appropriate solution would be to disable the respective timers during scan and re-enable them after scan but requires more complex code and testing. Cc: Christian Lamparter Cc: Larry Finger Reported-by: Fabio Rossi Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 807ab89bdad9..76c03daeb455 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1166,6 +1166,9 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, if (!netif_running(sdata->dev)) return; + if (sdata->local->scanning) + return; + mutex_lock(&ifmgd->mtx); if (!ifmgd->associated) @@ -2213,9 +2216,6 @@ static void ieee80211_sta_monitor_work(struct work_struct *work) container_of(work, struct ieee80211_sub_if_data, u.mgd.monitor_work); - if (sdata->local->scanning) - return; - ieee80211_mgd_probe_ap(sdata, false); } -- cgit v1.2.3 From 3fa52056f3a8e755708241d5795e6d3e6f55ad85 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Jul 2009 13:23:09 +0200 Subject: mac80211: fix PS-poll response, race When a station queries us for a PS-poll response, we wrongly queue the frame on the virtual interface's queue rather than the pending queue. Additionally, fix a race condition where we could potentially send multiple frames to the sleeping station due to using a station flag rather than a packet flag. When converting to a packet flag, we can also convert p54 and remove the filter clearing we added for it. (Also remove a now dead function) Signed-off-by: Johannes Berg Reported-by: Bob Copeland Tested-by: Bob Copeland Cc: Christian Lamparter Signed-off-by: John W. Linville --- net/mac80211/rx.c | 11 ++++++----- net/mac80211/sta_info.h | 13 ------------- net/mac80211/tx.c | 19 +------------------ 3 files changed, 7 insertions(+), 36 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index cb95a3116034..f195705146bd 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -783,7 +783,7 @@ static void ap_sta_ps_start(struct sta_info *sta) struct ieee80211_local *local = sdata->local; atomic_inc(&sdata->bss->num_sta_ps); - set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL); + set_sta_flags(sta, WLAN_STA_PS); drv_sta_notify(local, &sdata->vif, STA_NOTIFY_SLEEP, &sta->sta); #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n", @@ -799,7 +799,7 @@ static int ap_sta_ps_end(struct sta_info *sta) atomic_dec(&sdata->bss->num_sta_ps); - clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL); + clear_sta_flags(sta, WLAN_STA_PS); drv_sta_notify(local, &sdata->vif, STA_NOTIFY_AWAKE, &sta->sta); if (!skb_queue_empty(&sta->ps_tx_buf)) @@ -1117,14 +1117,15 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) skb_queue_empty(&rx->sta->ps_tx_buf); if (skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; /* - * Tell TX path to send one frame even though the STA may + * Tell TX path to send this frame even though the STA may * still remain is PS mode after this frame exchange. */ - set_sta_flags(rx->sta, WLAN_STA_PSPOLL); + info->flags |= IEEE80211_TX_CTL_PSPOLL_RESPONSE; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "STA %pM aid %d: PS Poll (entries after %d)\n", @@ -1139,7 +1140,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) else hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); - dev_queue_xmit(skb); + ieee80211_add_pending_skb(rx->local, skb); if (no_pending_pkts) sta_info_clear_tim_bit(rx->sta); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 4ecf10a9bd00..ccc3adf962c7 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -30,7 +30,6 @@ * @WLAN_STA_ASSOC_AP: We're associated to that station, it is an AP. * @WLAN_STA_WME: Station is a QoS-STA. * @WLAN_STA_WDS: Station is one of our WDS peers. - * @WLAN_STA_PSPOLL: Station has just PS-polled us. * @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the * IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next * frame to this station is transmitted. @@ -47,7 +46,6 @@ enum ieee80211_sta_info_flags { WLAN_STA_ASSOC_AP = 1<<5, WLAN_STA_WME = 1<<6, WLAN_STA_WDS = 1<<7, - WLAN_STA_PSPOLL = 1<<8, WLAN_STA_CLEAR_PS_FILT = 1<<9, WLAN_STA_MFP = 1<<10, WLAN_STA_SUSPEND = 1<<11 @@ -359,17 +357,6 @@ static inline void clear_sta_flags(struct sta_info *sta, const u32 flags) spin_unlock_irqrestore(&sta->flaglock, irqfl); } -static inline void set_and_clear_sta_flags(struct sta_info *sta, - const u32 set, const u32 clear) -{ - unsigned long irqfl; - - spin_lock_irqsave(&sta->flaglock, irqfl); - sta->flags |= set; - sta->flags &= ~clear; - spin_unlock_irqrestore(&sta->flaglock, irqfl); -} - static inline u32 test_sta_flags(struct sta_info *sta, const u32 flags) { u32 ret; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 70ff4f065665..edacad1fb1dc 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -373,7 +373,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) staflags = get_sta_flags(sta); if (unlikely((staflags & WLAN_STA_PS) && - !(staflags & WLAN_STA_PSPOLL))) { + !(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE))) { #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "STA %pM aid %d: PS buffer (entries " "before %d)\n", @@ -412,24 +412,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) sta->sta.addr); } #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - if (test_and_clear_sta_flags(sta, WLAN_STA_PSPOLL)) { - /* - * The sleeping station with pending data is now snoozing. - * It queried us for its buffered frames and will go back - * to deep sleep once it got everything. - * - * inform the driver, in case the hardware does powersave - * frame filtering and keeps a station blacklist on its own - * (e.g: p54), so that frames can be delivered unimpeded. - * - * Note: It should be safe to disable the filter now. - * As, it is really unlikely that we still have any pending - * frame for this station in the hw's buffers/fifos left, - * that is not rejected with a unsuccessful tx_status yet. - */ - info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; - } return TX_CONTINUE; } -- cgit v1.2.3 From 21f5fc75deca63bc41c9d13007d35981d4485622 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 24 Jul 2009 19:57:25 -0400 Subject: mac80211: fix oops due to missing private data This was caused by patch: "mac80211: cooperate more with network namespaces" The version of the patch applied doesn't match Johannes' latest: http://johannes.sipsolutions.net/patches/kernel/all/LATEST/NNN-mac80211-netns.patch The skb->cb virtual interface data wasn't being reset for reuse so ath9k pooped out when trying to dereference the private rate control info from the skb. BUG: unable to handle kernel NULL pointer dereference RIP: 0010:[] ath_tx_rc_status+0x33/0x150 [ath9k] <-- snip etc --> Reported-by: Davide Pesavento Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/mac80211/tx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index edacad1fb1dc..9e5dff1c8f27 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1170,13 +1170,15 @@ static int __ieee80211_tx(struct ieee80211_local *local, } ret = drv_tx(local, skb); - info->control.vif = &sdata->vif; if (WARN_ON(ret != NETDEV_TX_OK && skb->len != len)) { dev_kfree_skb(skb); ret = NETDEV_TX_OK; } - if (ret != NETDEV_TX_OK) + if (ret != NETDEV_TX_OK) { + info->control.vif = &sdata->vif; return IEEE80211_TX_AGAIN; + } + *skbp = skb = next; ieee80211_led_tx(local, 1); fragm = true; -- cgit v1.2.3 From 8d8b261a5c11bd043b9b0e0c7e6c49d57611e3ae Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 25 Jul 2009 11:58:36 +0200 Subject: mac80211: fix receiving deauth Marcel reported a warning, which quite obviously comes from an oversight in the code handling deauth frames, and which resulted in multiple follow-up warnings due to this missing handling. This patch adds the missing deauth handling (telling cfg80211 about it) and also removes the follow-up warnings since they could happen due to races even if nothing is wrong. I've explained the races in the comments. Signed-off-by: Johannes Berg Reported-by: Marcel Holtmann Tested-by: Marcel Holtmann Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 76c03daeb455..f60a83102ea2 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2003,6 +2003,9 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, case RX_MGMT_CFG80211_ASSOC: cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, skb->len); break; + case RX_MGMT_CFG80211_DEAUTH: + cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len, NULL); + break; default: WARN(1, "unexpected: %d", rma); } @@ -2498,8 +2501,13 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, } } - /* cfg80211 should catch this... */ - if (WARN_ON(!bssid)) { + /* + * cfg80211 should catch this ... but it's racy since + * we can receive a deauth frame, process it, hand it + * to cfg80211 while that's in a locked section already + * trying to tell us that the user wants to disconnect. + */ + if (!bssid) { mutex_unlock(&ifmgd->mtx); return -ENOLINK; } @@ -2524,8 +2532,13 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, mutex_lock(&ifmgd->mtx); - /* cfg80211 should catch that */ - if (WARN_ON(&ifmgd->associated->cbss != req->bss)) { + /* + * cfg80211 should catch this ... but it's racy since + * we can receive a disassoc frame, process it, hand it + * to cfg80211 while that's in a locked section already + * trying to tell us that the user wants to disconnect. + */ + if (&ifmgd->associated->cbss != req->bss) { mutex_unlock(&ifmgd->mtx); return -ENOLINK; } -- cgit v1.2.3 From 0ee9c13c7c92581ab005d80795cf65897213b249 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sat, 25 Jul 2009 17:25:51 +0200 Subject: mac80211: fix an oops in ieee80211_scan_state_set_channel Fix an oops in ieee80211_scan_state_set_channel which was triggered if the last scanned channel was skipped (for example due to regulatory restrictions) by returning to the decision state after each skipped channel. Signed-off-by: Helmut Schaa Signed-off-by: John W. Linville --- net/mac80211/scan.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index b376775e722f..147772a2977c 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -605,8 +605,11 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, /* advance state machine to next channel/band */ local->scan_channel_idx++; - if (skip) + if (skip) { + /* if we skip this channel return to the decision state */ + local->next_scan_state = SCAN_DECISION; return; + } /* * Probe delay is used to update the NAV, cf. 11.1.3.2.2 -- cgit v1.2.3 From a7bc376c858e0e724b8cb2db09b6874562d377ca Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Jul 2009 10:33:31 +0200 Subject: mac80211: verify info->control.vif is not NULL When enqueuing packets on the internal packet queue, we need to ensure that we have a valid vif pointer since that is required since the net namespace work. Add some assertions to verify this, but also don't crash is for some reason we don't end up with a vif pointer -- warn and drop the packet in all these cases. Since this code touches a number of hotpaths, it is intended to be temporary, or maybe configurable in the future, at least the bit that is in the path that gets hit for every packet, ieee80211_tx_pending(). Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/tx.c | 5 +++++ net/mac80211/util.c | 13 +++++++++++++ 2 files changed, 18 insertions(+) (limited to 'net/mac80211') diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 9e5dff1c8f27..4e1b2ba122cd 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1889,6 +1889,11 @@ void ieee80211_tx_pending(unsigned long data) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_sub_if_data *sdata; + if (WARN_ON(!info->control.vif)) { + kfree_skb(skb); + continue; + } + sdata = vif_to_sdata(info->control.vif); dev_hold(sdata->dev); spin_unlock_irqrestore(&local->queue_stop_reason_lock, diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 7fc55846d601..8502936e5314 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -336,6 +336,12 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local, struct ieee80211_hw *hw = &local->hw; unsigned long flags; int queue = skb_get_queue_mapping(skb); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + if (WARN_ON(!info->control.vif)) { + kfree(skb); + return; + } spin_lock_irqsave(&local->queue_stop_reason_lock, flags); __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); @@ -358,6 +364,13 @@ int ieee80211_add_pending_skbs(struct ieee80211_local *local, IEEE80211_QUEUE_STOP_REASON_SKB_ADD); while ((skb = skb_dequeue(skbs))) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + if (WARN_ON(!info->control.vif)) { + kfree(skb); + continue; + } + ret++; queue = skb_get_queue_mapping(skb); __skb_queue_tail(&local->pending[queue], skb); -- cgit v1.2.3 From 0e82ffe3b90bcad72cfe80e4379946b8fb0691ca Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Jul 2009 12:01:50 +0200 Subject: cfg80211: combine iwfreq implementations Until now we implemented iwfreq for managed mode, we needed to keep the implementations separate, but now that we have all versions implemented we can combine them and export just one handler. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/wext.c | 73 ++--------------------------------------------------- 1 file changed, 2 insertions(+), 71 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 5acb8140ee58..7cd9aa79ef52 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -27,75 +27,6 @@ #include "aes_ccm.h" -static int ieee80211_ioctl_siwfreq(struct net_device *dev, - struct iw_request_info *info, - struct iw_freq *freq, char *extra) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_local *local = sdata->local; - struct ieee80211_channel *chan; - - if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra); - else if (sdata->vif.type == NL80211_IFTYPE_STATION) - return cfg80211_mgd_wext_siwfreq(dev, info, freq, extra); - - /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */ - if (freq->e == 0) { - if (freq->m < 0) - return -EINVAL; - else - chan = ieee80211_get_channel(local->hw.wiphy, - ieee80211_channel_to_frequency(freq->m)); - } else { - int i, div = 1000000; - for (i = 0; i < freq->e; i++) - div /= 10; - if (div <= 0) - return -EINVAL; - chan = ieee80211_get_channel(local->hw.wiphy, freq->m / div); - } - - if (!chan) - return -EINVAL; - - if (chan->flags & IEEE80211_CHAN_DISABLED) - return -EINVAL; - - /* - * no change except maybe auto -> fixed, ignore the HT - * setting so you can fix a channel you're on already - */ - if (local->oper_channel == chan) - return 0; - - local->oper_channel = chan; - local->oper_channel_type = NL80211_CHAN_NO_HT; - ieee80211_hw_config(local, 0); - - return 0; -} - - -static int ieee80211_ioctl_giwfreq(struct net_device *dev, - struct iw_request_info *info, - struct iw_freq *freq, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); - else if (sdata->vif.type == NL80211_IFTYPE_STATION) - return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra); - - freq->m = local->oper_channel->center_freq; - freq->e = 6; - - return 0; -} - - static int ieee80211_ioctl_siwessid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *ssid) @@ -173,8 +104,8 @@ static const iw_handler ieee80211_handler[] = (iw_handler) cfg80211_wext_giwname, /* SIOCGIWNAME */ (iw_handler) NULL, /* SIOCSIWNWID */ (iw_handler) NULL, /* SIOCGIWNWID */ - (iw_handler) ieee80211_ioctl_siwfreq, /* SIOCSIWFREQ */ - (iw_handler) ieee80211_ioctl_giwfreq, /* SIOCGIWFREQ */ + (iw_handler) cfg80211_wext_siwfreq, /* SIOCSIWFREQ */ + (iw_handler) cfg80211_wext_giwfreq, /* SIOCGIWFREQ */ (iw_handler) cfg80211_wext_siwmode, /* SIOCSIWMODE */ (iw_handler) cfg80211_wext_giwmode, /* SIOCGIWMODE */ (iw_handler) NULL, /* SIOCSIWSENS */ -- cgit v1.2.3 From 562e482265ac4d660d9f0114419591d62f44361d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Jul 2009 12:01:51 +0200 Subject: cfg80211: combine IWAP handlers Since we now have IWAP handlers for all modes, we can combine them into one. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/wext.c | 41 ++--------------------------------------- 1 file changed, 2 insertions(+), 39 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 7cd9aa79ef52..72866c8b8c3d 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -59,43 +59,6 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev, } -static int ieee80211_ioctl_siwap(struct net_device *dev, - struct iw_request_info *info, - struct sockaddr *ap_addr, char *extra) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); - - if (sdata->vif.type == NL80211_IFTYPE_STATION) - return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra); - - if (sdata->vif.type == NL80211_IFTYPE_WDS) - return cfg80211_wds_wext_siwap(dev, info, ap_addr, extra); - return -EOPNOTSUPP; -} - - -static int ieee80211_ioctl_giwap(struct net_device *dev, - struct iw_request_info *info, - struct sockaddr *ap_addr, char *extra) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra); - - if (sdata->vif.type == NL80211_IFTYPE_STATION) - return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra); - - if (sdata->vif.type == NL80211_IFTYPE_WDS) - return cfg80211_wds_wext_giwap(dev, info, ap_addr, extra); - - return -EOPNOTSUPP; -} - - /* Structures to export the Wireless Handlers */ static const iw_handler ieee80211_handler[] = @@ -120,8 +83,8 @@ static const iw_handler ieee80211_handler[] = (iw_handler) NULL, /* SIOCGIWSPY */ (iw_handler) NULL, /* SIOCSIWTHRSPY */ (iw_handler) NULL, /* SIOCGIWTHRSPY */ - (iw_handler) ieee80211_ioctl_siwap, /* SIOCSIWAP */ - (iw_handler) ieee80211_ioctl_giwap, /* SIOCGIWAP */ + (iw_handler) cfg80211_wext_siwap, /* SIOCSIWAP */ + (iw_handler) cfg80211_wext_giwap, /* SIOCGIWAP */ (iw_handler) cfg80211_wext_siwmlme, /* SIOCSIWMLME */ (iw_handler) NULL, /* SIOCGIWAPLIST */ (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */ -- cgit v1.2.3 From 1f9298f96082692bdfe73af6fc2167f627f21647 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Jul 2009 12:01:52 +0200 Subject: cfg80211: combine IWESSID handlers Since we now have handlers IWESSID for all modes, we can combine them into one. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/wext.c | 35 ++--------------------------------- 1 file changed, 2 insertions(+), 33 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 72866c8b8c3d..aa250c3e8fda 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -27,37 +27,6 @@ #include "aes_ccm.h" -static int ieee80211_ioctl_siwessid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *ssid) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - return cfg80211_ibss_wext_siwessid(dev, info, data, ssid); - else if (sdata->vif.type == NL80211_IFTYPE_STATION) - return cfg80211_mgd_wext_siwessid(dev, info, data, ssid); - - return -EOPNOTSUPP; -} - - -static int ieee80211_ioctl_giwessid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *ssid) -{ - struct ieee80211_sub_if_data *sdata; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (sdata->vif.type == NL80211_IFTYPE_ADHOC) - return cfg80211_ibss_wext_giwessid(dev, info, data, ssid); - else if (sdata->vif.type == NL80211_IFTYPE_STATION) - return cfg80211_mgd_wext_giwessid(dev, info, data, ssid); - - return -EOPNOTSUPP; -} - /* Structures to export the Wireless Handlers */ @@ -89,8 +58,8 @@ static const iw_handler ieee80211_handler[] = (iw_handler) NULL, /* SIOCGIWAPLIST */ (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */ (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */ - (iw_handler) ieee80211_ioctl_siwessid, /* SIOCSIWESSID */ - (iw_handler) ieee80211_ioctl_giwessid, /* SIOCGIWESSID */ + (iw_handler) cfg80211_wext_siwessid, /* SIOCSIWESSID */ + (iw_handler) cfg80211_wext_giwessid, /* SIOCGIWESSID */ (iw_handler) NULL, /* SIOCSIWNICKN */ (iw_handler) NULL, /* SIOCGIWNICKN */ (iw_handler) NULL, /* -- hole -- */ -- cgit v1.2.3 From a9a11622c5c742c115fad371c0397ae86dd3bb67 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Jul 2009 12:01:53 +0200 Subject: cfg80211: self-contained wext handling where possible Finally! This is what you've all been waiting for! This patch makes cfg80211 take care of wext emulation _completely_ by itself, drivers that don't need things cfg80211 doesn't do yet don't even need to be aware of wireless extensions. This means we can also clean up mac80211's and iwm's Kconfig and make it possible to build them w/o wext now! RIP wext. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/Kconfig | 1 - net/mac80211/Makefile | 1 - net/mac80211/ieee80211_i.h | 4 -- net/mac80211/iface.c | 1 - net/mac80211/scan.c | 1 - net/mac80211/wext.c | 98 ---------------------------------------------- 6 files changed, 106 deletions(-) delete mode 100644 net/mac80211/wext.c (limited to 'net/mac80211') diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 19a4c66e143e..7dd77b6d4c9a 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -6,7 +6,6 @@ config MAC80211 select CRYPTO_ARC4 select CRYPTO_AES select CRC32 - select WIRELESS_EXT ---help--- This option enables the hardware independent IEEE 802.11 networking stack. diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 91284a74ff91..9f3cf7129324 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -3,7 +3,6 @@ obj-$(CONFIG_MAC80211) += mac80211.o # mac80211 objects mac80211-y := \ main.o \ - wext.o \ sta_info.o \ wep.o \ wpa.o \ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c6b25cb73284..aec6853cb435 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -24,7 +24,6 @@ #include #include #include -#include #include #include "key.h" #include "sta_info.h" @@ -951,9 +950,6 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, void ieee80211_configure_filter(struct ieee80211_local *local); u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata); -/* wireless extensions */ -extern const struct iw_handler_def ieee80211_iw_handler_def; - /* STA code */ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata); int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index d79a21105042..6c655b6547fb 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -684,7 +684,6 @@ static void ieee80211_if_setup(struct net_device *dev) { ether_setup(dev); dev->netdev_ops = &ieee80211_dataif_ops; - dev->wireless_handlers = &ieee80211_iw_handler_def; dev->destructor = free_netdev; } diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 147772a2977c..45731000eb8d 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -18,7 +18,6 @@ #include #include #include -#include #include "ieee80211_i.h" #include "driver-ops.h" diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c deleted file mode 100644 index aa250c3e8fda..000000000000 --- a/net/mac80211/wext.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2002-2005, Instant802 Networks, Inc. - * Copyright 2005-2006, Devicescape Software, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "ieee80211_i.h" -#include "led.h" -#include "rate.h" -#include "wpa.h" -#include "aes_ccm.h" - - - -/* Structures to export the Wireless Handlers */ - -static const iw_handler ieee80211_handler[] = -{ - (iw_handler) NULL, /* SIOCSIWCOMMIT */ - (iw_handler) cfg80211_wext_giwname, /* SIOCGIWNAME */ - (iw_handler) NULL, /* SIOCSIWNWID */ - (iw_handler) NULL, /* SIOCGIWNWID */ - (iw_handler) cfg80211_wext_siwfreq, /* SIOCSIWFREQ */ - (iw_handler) cfg80211_wext_giwfreq, /* SIOCGIWFREQ */ - (iw_handler) cfg80211_wext_siwmode, /* SIOCSIWMODE */ - (iw_handler) cfg80211_wext_giwmode, /* SIOCGIWMODE */ - (iw_handler) NULL, /* SIOCSIWSENS */ - (iw_handler) NULL, /* SIOCGIWSENS */ - (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ - (iw_handler) cfg80211_wext_giwrange, /* SIOCGIWRANGE */ - (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ - (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ - (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ - (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */ - (iw_handler) NULL, /* SIOCSIWSPY */ - (iw_handler) NULL, /* SIOCGIWSPY */ - (iw_handler) NULL, /* SIOCSIWTHRSPY */ - (iw_handler) NULL, /* SIOCGIWTHRSPY */ - (iw_handler) cfg80211_wext_siwap, /* SIOCSIWAP */ - (iw_handler) cfg80211_wext_giwap, /* SIOCGIWAP */ - (iw_handler) cfg80211_wext_siwmlme, /* SIOCSIWMLME */ - (iw_handler) NULL, /* SIOCGIWAPLIST */ - (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */ - (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */ - (iw_handler) cfg80211_wext_siwessid, /* SIOCSIWESSID */ - (iw_handler) cfg80211_wext_giwessid, /* SIOCGIWESSID */ - (iw_handler) NULL, /* SIOCSIWNICKN */ - (iw_handler) NULL, /* SIOCGIWNICKN */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) cfg80211_wext_siwrate, /* SIOCSIWRATE */ - (iw_handler) cfg80211_wext_giwrate, /* SIOCGIWRATE */ - (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */ - (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */ - (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */ - (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */ - (iw_handler) cfg80211_wext_siwtxpower, /* SIOCSIWTXPOW */ - (iw_handler) cfg80211_wext_giwtxpower, /* SIOCGIWTXPOW */ - (iw_handler) cfg80211_wext_siwretry, /* SIOCSIWRETRY */ - (iw_handler) cfg80211_wext_giwretry, /* SIOCGIWRETRY */ - (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */ - (iw_handler) cfg80211_wext_giwencode, /* SIOCGIWENCODE */ - (iw_handler) cfg80211_wext_siwpower, /* SIOCSIWPOWER */ - (iw_handler) cfg80211_wext_giwpower, /* SIOCGIWPOWER */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) cfg80211_wext_siwgenie, /* SIOCSIWGENIE */ - (iw_handler) NULL, /* SIOCGIWGENIE */ - (iw_handler) cfg80211_wext_siwauth, /* SIOCSIWAUTH */ - (iw_handler) cfg80211_wext_giwauth, /* SIOCGIWAUTH */ - (iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */ - (iw_handler) NULL, /* SIOCGIWENCODEEXT */ - (iw_handler) NULL, /* SIOCSIWPMKSA */ - (iw_handler) NULL, /* -- hole -- */ -}; - -const struct iw_handler_def ieee80211_iw_handler_def = -{ - .num_standard = ARRAY_SIZE(ieee80211_handler), - .standard = (iw_handler *) ieee80211_handler, - .get_wireless_stats = cfg80211_wireless_stats, -}; -- cgit v1.2.3 From 4da163ab0a224590f3cae67c1d54ae8c428f6223 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 27 Jul 2009 20:28:40 +0200 Subject: mac80211: disable software retry for now Pavel Roskin reported a problem that seems to be due to software retry of already transmitted frames. It turns out that we've never done that correctly, but due to some recent changes it now crashes in the TX code. I've added a comment in the patch that explains the problem better and also points to possible solutions -- which I can't implement right now. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/main.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'net/mac80211') diff --git a/net/mac80211/main.c b/net/mac80211/main.c index c1a799194fff..9dd8d25611e0 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -310,6 +310,31 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + /* + * XXX: This is temporary! + * + * The problem here is that when we get here, the driver will + * quite likely have pretty much overwritten info->control by + * using info->driver_data or info->rate_driver_data. Thus, + * when passing out the frame to the driver again, we would be + * passing completely bogus data since the driver would then + * expect a properly filled info->control. In mac80211 itself + * the same problem occurs, since we need info->control.vif + * internally. + * + * To fix this, we should send the frame through TX processing + * again. However, it's not that simple, since the frame will + * have been software-encrypted (if applicable) already, and + * encrypting it again doesn't do much good. So to properly do + * that, we not only have to skip the actual 'raw' encryption + * (key selection etc. still has to be done!) but also the + * sequence number assignment since that impacts the crypto + * encapsulation, of course. + * + * Hence, for now, fix the bug by just dropping the frame. + */ + goto drop; + sta->tx_filtered_count++; /* @@ -363,6 +388,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, return; } + drop: #ifdef CONFIG_MAC80211_VERBOSE_DEBUG if (net_ratelimit()) printk(KERN_DEBUG "%s: dropped TX filtered frame, " -- cgit v1.2.3 From 97af743207466ff8b477e14bfb7af0ba2c93375b Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Wed, 29 Jul 2009 10:13:03 +0200 Subject: mac80211: disable beacons before removing the associated interface When downing interfaces, it's a good idea to tell the driver to stop sending beacons; that way the driver doesn't need special code in ops->remove_interface() when it should already handle the case in bss_info_changed(). This fixes a potential crash with at least ath5k since the vif pointer will be nullified while beacon interrupts are still active. Signed-off-by: Bob Copeland Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/iface.c | 10 ++++++++++ net/mac80211/main.c | 3 ++- net/mac80211/pm.c | 4 ++++ 3 files changed, 16 insertions(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 6c655b6547fb..6614d4ff273d 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -522,6 +522,16 @@ static int ieee80211_stop(struct net_device *dev) ieee80211_scan_completed(&local->hw, true); } + /* + * Disable beaconing for AP and mesh, IBSS can't + * still be joined to a network at this point. + */ + if (sdata->vif.type == NL80211_IFTYPE_AP || + sdata->vif.type == NL80211_IFTYPE_MESH_POINT) { + ieee80211_bss_info_change_notify(sdata, + BSS_CHANGED_BEACON_ENABLED); + } + conf.vif = &sdata->vif; conf.type = sdata->vif.type; conf.mac_addr = dev->dev_addr; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 9dd8d25611e0..5e76dd1daf71 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -198,7 +198,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, } if (changed & BSS_CHANGED_BEACON_ENABLED) { - if (test_bit(SCAN_SW_SCANNING, &local->scanning)) { + if (local->quiescing || !netif_running(sdata->dev) || + test_bit(SCAN_SW_SCANNING, &local->scanning)) { sdata->vif.bss_conf.enable_beacon = false; } else { /* diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 5e3d476972f9..3320f7daaf25 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -96,6 +96,10 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) if (!netif_running(sdata->dev)) continue; + /* disable beaconing */ + ieee80211_bss_info_change_notify(sdata, + BSS_CHANGED_BEACON_ENABLED); + conf.vif = &sdata->vif; conf.type = sdata->vif.type; conf.mac_addr = sdata->dev->dev_addr; -- cgit v1.2.3 From 57c9fff3d0c5d77bc7910717faeca4e8a018b1ee Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 29 Jul 2009 15:46:21 +0200 Subject: mac80211: fix sparse warnings/errors sparse complains about a shadowed variable, which we can just rename, and lots of stuff if the API tracer is enabled, so kick out the tracer code in a sparse run -- the macros just confuse it. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/driver-trace.c | 3 +++ net/mac80211/iface.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/driver-trace.c b/net/mac80211/driver-trace.c index 6da6f79932fc..8ed8711b1a6d 100644 --- a/net/mac80211/driver-trace.c +++ b/net/mac80211/driver-trace.c @@ -1,6 +1,9 @@ /* bug in tracepoint.h, it should include this */ #include +/* sparse isn't too happy with all macros... */ +#ifndef __CHECKER__ #include "driver-ops.h" #define CREATE_TRACE_POINTS #include "driver-trace.h" +#endif diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 6614d4ff273d..a83087f4237d 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -401,7 +401,7 @@ static int ieee80211_stop(struct net_device *dev) /* APs need special treatment */ if (sdata->vif.type == NL80211_IFTYPE_AP) { - struct ieee80211_sub_if_data *vlan, *tmp; + struct ieee80211_sub_if_data *vlan, *tmpsdata; struct beacon_data *old_beacon = sdata->u.ap.beacon; /* remove beacon */ @@ -410,7 +410,7 @@ static int ieee80211_stop(struct net_device *dev) kfree(old_beacon); /* down all dependent devices, that is VLANs */ - list_for_each_entry_safe(vlan, tmp, &sdata->u.ap.vlans, + list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, u.vlan.list) dev_close(vlan->dev); WARN_ON(!list_empty(&sdata->u.ap.vlans)); -- cgit v1.2.3 From 42935ecaf4e784d0815afa9a7e5fe7e141157ca3 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 29 Jul 2009 20:08:07 -0400 Subject: mac80211: redefine usage of the mac80211 workqueue The mac80211 workqueue exists to enable mac80211 and drivers to queue their own work on a single threaded workqueue. mac80211 takes care to flush the workqueue during suspend but we never really had requirements on drivers for how they should use the workqueue in consideration for suspend. We extend mac80211 to document how the mac80211 workqueue should be used, how it should not be used and finally move raw access to the workqueue to mac80211 only. Drivers and mac80211 use helpers to queue work onto the mac80211 workqueue: * ieee80211_queue_work() * ieee80211_queue_delayed_work() These helpers will now warn if mac80211 already completed its suspend cycle and someone is trying to queue work. mac80211 flushes the mac80211 workqueue prior to suspend a few times, but we haven't taken the care to ensure drivers won't add more work after suspend. To help with this we add a warning when someone tries to add work and mac80211 already completed the suspend cycle. Drivers should ensure they cancel any work or delayed work in the mac80211 stop() callback. Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/mac80211/ibss.c | 6 +++--- net/mac80211/ieee80211_i.h | 6 ++++++ net/mac80211/iface.c | 4 ++-- net/mac80211/main.c | 8 ++++---- net/mac80211/mesh.c | 10 +++++----- net/mac80211/mesh_hwmp.c | 4 ++-- net/mac80211/mlme.c | 48 +++++++++++++++++++++------------------------- net/mac80211/pm.c | 4 ++-- net/mac80211/scan.c | 8 ++++---- net/mac80211/tx.c | 2 +- net/mac80211/util.c | 41 +++++++++++++++++++++++++++++++++++++++ 11 files changed, 92 insertions(+), 49 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 6e3cca65c460..920ec8792f4b 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -781,7 +781,7 @@ static void ieee80211_ibss_timer(unsigned long data) } set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request); - queue_work(local->hw.workqueue, &ifibss->work); + ieee80211_queue_work(&local->hw, &ifibss->work); } #ifdef CONFIG_PM @@ -853,7 +853,7 @@ ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) case IEEE80211_STYPE_PROBE_REQ: case IEEE80211_STYPE_AUTH: skb_queue_tail(&sdata->u.ibss.skb_queue, skb); - queue_work(local->hw.workqueue, &sdata->u.ibss.work); + ieee80211_queue_work(&local->hw, &sdata->u.ibss.work); return RX_QUEUED; } @@ -912,7 +912,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, ieee80211_recalc_idle(sdata->local); set_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request); - queue_work(sdata->local->hw.workqueue, &sdata->u.ibss.work); + ieee80211_queue_work(&sdata->local->hw, &sdata->u.ibss.work); return 0; } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index aec6853cb435..316825be2019 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -614,6 +614,12 @@ struct ieee80211_local { const struct ieee80211_ops *ops; + /* + * private workqueue to mac80211. mac80211 makes this accessible + * via ieee80211_queue_work() + */ + struct workqueue_struct *workqueue; + unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES]; /* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */ spinlock_t queue_stop_reason_lock; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index a83087f4237d..8c1284d45e69 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -312,7 +312,7 @@ static int ieee80211_open(struct net_device *dev) * to fix this. */ if (sdata->vif.type == NL80211_IFTYPE_STATION) - queue_work(local->hw.workqueue, &sdata->u.mgd.work); + ieee80211_queue_work(&local->hw, &sdata->u.mgd.work); netif_tx_start_all_queues(dev); @@ -551,7 +551,7 @@ static int ieee80211_stop(struct net_device *dev) ieee80211_led_radio(local, false); - flush_workqueue(local->hw.workqueue); + flush_workqueue(local->workqueue); tasklet_disable(&local->tx_pending_tasklet); tasklet_disable(&local->tasklet); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 5e76dd1daf71..22e07385ff60 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -821,9 +821,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (hw->queues > IEEE80211_MAX_QUEUES) hw->queues = IEEE80211_MAX_QUEUES; - local->hw.workqueue = + local->workqueue = create_singlethread_workqueue(wiphy_name(local->hw.wiphy)); - if (!local->hw.workqueue) { + if (!local->workqueue) { result = -ENOMEM; goto fail_workqueue; } @@ -913,7 +913,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) sta_info_stop(local); fail_sta_info: debugfs_hw_del(local); - destroy_workqueue(local->hw.workqueue); + destroy_workqueue(local->workqueue); fail_workqueue: wiphy_unregister(local->hw.wiphy); fail_wiphy_register: @@ -955,7 +955,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) skb_queue_purge(&local->skb_queue); skb_queue_purge(&local->skb_queue_unreliable); - destroy_workqueue(local->hw.workqueue); + destroy_workqueue(local->workqueue); wiphy_unregister(local->hw.wiphy); ieee80211_wep_free(local); ieee80211_led_exit(local); diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 9a3826978b1c..2f4f518ab45c 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -54,7 +54,7 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data) return; } - queue_work(local->hw.workqueue, &ifmsh->work); + ieee80211_queue_work(local->hw.workqueue, &ifmsh->work); } /** @@ -357,7 +357,7 @@ static void ieee80211_mesh_path_timer(unsigned long data) return; } - queue_work(local->hw.workqueue, &ifmsh->work); + ieee80211_queue_work(local->hw.workqueue, &ifmsh->work); } struct mesh_table *mesh_table_grow(struct mesh_table *tbl) @@ -471,7 +471,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) struct ieee80211_local *local = sdata->local; ifmsh->housekeeping = true; - queue_work(local->hw.workqueue, &ifmsh->work); + ieee80211_queue_work(local->hw.workqueue, &ifmsh->work); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED); } @@ -619,7 +619,7 @@ void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) if (ieee80211_vif_is_mesh(&sdata->vif)) - queue_work(local->hw.workqueue, &sdata->u.mesh.work); + ieee80211_queue_work(local->hw.workqueue, &sdata->u.mesh.work); rcu_read_unlock(); } @@ -692,7 +692,7 @@ ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) case IEEE80211_STYPE_PROBE_RESP: case IEEE80211_STYPE_BEACON: skb_queue_tail(&ifmsh->skb_queue, skb); - queue_work(local->hw.workqueue, &ifmsh->work); + ieee80211_queue_work(local->hw.workqueue, &ifmsh->work); return RX_QUEUED; } diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index e93c37ef6a48..11ab71a68ff9 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -660,14 +660,14 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags) spin_unlock(&ifmsh->mesh_preq_queue_lock); if (time_after(jiffies, ifmsh->last_preq + min_preq_int_jiff(sdata))) - queue_work(sdata->local->hw.workqueue, &ifmsh->work); + ieee80211_queue_work(sdata->local->hw.workqueue, &ifmsh->work); else if (time_before(jiffies, ifmsh->last_preq)) { /* avoid long wait if did not send preqs for a long time * and jiffies wrapped around */ ifmsh->last_preq = jiffies - min_preq_int_jiff(sdata) - 1; - queue_work(sdata->local->hw.workqueue, &ifmsh->work); + ieee80211_queue_work(sdata->local->hw.workqueue, &ifmsh->work); } else mod_timer(&ifmsh->mesh_path_timer, ifmsh->last_preq + min_preq_int_jiff(sdata)); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index ee83125ed179..0779ba150b26 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -565,7 +565,7 @@ static void ieee80211_chswitch_timer(unsigned long data) return; } - queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work); + ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); } void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, @@ -597,7 +597,7 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, sdata->local->csa_channel = new_ch; if (sw_elem->count <= 1) { - queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work); + ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); } else { ieee80211_stop_queues_by_reason(&sdata->local->hw, IEEE80211_QUEUE_STOP_REASON_CSA); @@ -763,7 +763,7 @@ void ieee80211_dynamic_ps_timer(unsigned long data) if (local->quiescing || local->suspended) return; - queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work); + ieee80211_queue_work(&local->hw, &local->dynamic_ps_enable_work); } /* MLME */ @@ -950,7 +950,7 @@ ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, * due to work needing to be done. Hence, queue the STAs work * again for that. */ - queue_work(local->hw.workqueue, &ifmgd->work); + ieee80211_queue_work(&local->hw, &ifmgd->work); return RX_MGMT_CFG80211_AUTH_TO; } @@ -995,7 +995,7 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, * due to work needing to be done. Hence, queue the STAs work * again for that. */ - queue_work(local->hw.workqueue, &ifmgd->work); + ieee80211_queue_work(&local->hw, &ifmgd->work); return RX_MGMT_CFG80211_AUTH_TO; } @@ -1124,7 +1124,7 @@ ieee80211_associate(struct ieee80211_sub_if_data *sdata, * due to work needing to be done. Hence, queue the STAs work * again for that. */ - queue_work(local->hw.workqueue, &ifmgd->work); + ieee80211_queue_work(&local->hw, &ifmgd->work); return RX_MGMT_CFG80211_ASSOC_TO; } @@ -1232,8 +1232,7 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif) { struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); - queue_work(sdata->local->hw.workqueue, - &sdata->u.mgd.beacon_loss_work); + ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.beacon_loss_work); } EXPORT_SYMBOL(ieee80211_beacon_loss); @@ -1888,7 +1887,7 @@ ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, case IEEE80211_STYPE_DISASSOC: case IEEE80211_STYPE_ACTION: skb_queue_tail(&sdata->u.mgd.skb_queue, skb); - queue_work(local->hw.workqueue, &sdata->u.mgd.work); + ieee80211_queue_work(&local->hw, &sdata->u.mgd.work); return RX_QUEUED; } @@ -2026,7 +2025,7 @@ static void ieee80211_sta_timer(unsigned long data) return; } - queue_work(local->hw.workqueue, &ifmgd->work); + ieee80211_queue_work(&local->hw, &ifmgd->work); } static void ieee80211_sta_work(struct work_struct *work) @@ -2051,13 +2050,11 @@ static void ieee80211_sta_work(struct work_struct *work) return; /* - * Nothing should have been stuffed into the workqueue during - * the suspend->resume cycle. If this WARN is seen then there - * is a bug with either the driver suspend or something in - * mac80211 stuffing into the workqueue which we haven't yet - * cleared during mac80211's suspend cycle. + * ieee80211_queue_work() should have picked up most cases, + * here we'll pick the the rest. */ - if (WARN_ON(local->suspended)) + if (WARN(local->suspended, "STA MLME work scheduled while " + "going to suspend\n")) return; ifmgd = &sdata->u.mgd; @@ -2113,9 +2110,9 @@ static void ieee80211_sta_work(struct work_struct *work) mutex_unlock(&ifmgd->mtx); if (test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) - queue_delayed_work(local->hw.workqueue, - &local->scan_work, - round_jiffies_relative(0)); + ieee80211_queue_delayed_work(&local->hw, + &local->scan_work, + round_jiffies_relative(0)); return; } @@ -2196,8 +2193,7 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data) if (local->quiescing) return; - queue_work(sdata->local->hw.workqueue, - &sdata->u.mgd.beacon_loss_work); + ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.beacon_loss_work); } static void ieee80211_sta_conn_mon_timer(unsigned long data) @@ -2210,7 +2206,7 @@ static void ieee80211_sta_conn_mon_timer(unsigned long data) if (local->quiescing) return; - queue_work(local->hw.workqueue, &ifmgd->monitor_work); + ieee80211_queue_work(&local->hw, &ifmgd->monitor_work); } static void ieee80211_sta_monitor_work(struct work_struct *work) @@ -2229,10 +2225,10 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) IEEE80211_STA_CONNECTION_POLL); /* let's probe the connection once */ - queue_work(sdata->local->hw.workqueue, + ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.monitor_work); /* and do all the other regular work too */ - queue_work(sdata->local->hw.workqueue, + ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work); } } @@ -2393,7 +2389,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, list_add(&wk->list, &sdata->u.mgd.work_list); mutex_unlock(&ifmgd->mtx); - queue_work(sdata->local->hw.workqueue, &sdata->u.mgd.work); + ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work); return 0; } @@ -2467,7 +2463,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, else ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT; - queue_work(sdata->local->hw.workqueue, &sdata->u.mgd.work); + ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work); err = 0; diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 3320f7daaf25..a5d2f1fb4417 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -26,7 +26,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) /* make quiescing visible to timers everywhere */ mb(); - flush_workqueue(local->hw.workqueue); + flush_workqueue(local->workqueue); /* Don't try to run timers while suspended. */ del_timer_sync(&local->sta_cleanup); @@ -117,7 +117,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) * shouldn't be doing (or cancel everything in the * stop callback) that but better safe than sorry. */ - flush_workqueue(local->hw.workqueue); + flush_workqueue(local->workqueue); local->suspended = true; /* need suspended to be visible before quiescing is false */ diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 45731000eb8d..244f53f3c8b4 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -385,8 +385,9 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) spin_unlock_bh(&local->filter_lock); /* TODO: start scan as soon as all nullfunc frames are ACKed */ - queue_delayed_work(local->hw.workqueue, &local->scan_work, - IEEE80211_CHANNEL_TIME); + ieee80211_queue_delayed_work(&local->hw, + &local->scan_work, + IEEE80211_CHANNEL_TIME); return 0; } @@ -715,8 +716,7 @@ void ieee80211_scan_work(struct work_struct *work) } } while (next_delay == 0); - queue_delayed_work(local->hw.workqueue, &local->scan_work, - next_delay); + ieee80211_queue_delayed_work(&local->hw, &local->scan_work, next_delay); } int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 4e1b2ba122cd..7cffaa046b33 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1400,7 +1400,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, if (local->hw.conf.flags & IEEE80211_CONF_PS) { ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_QUEUE_STOP_REASON_PS); - queue_work(local->hw.workqueue, + ieee80211_queue_work(&local->hw, &local->dynamic_ps_disable_work); } diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 8502936e5314..e55d57f559ec 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -511,6 +511,46 @@ void ieee80211_iterate_active_interfaces_atomic( } EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); +/* + * Nothing should have been stuffed into the workqueue during + * the suspend->resume cycle. If this WARN is seen then there + * is a bug with either the driver suspend or something in + * mac80211 stuffing into the workqueue which we haven't yet + * cleared during mac80211's suspend cycle. + */ +static bool ieee80211_can_queue_work(struct ieee80211_local *local) +{ + if (WARN(local->suspended, "queueing ieee80211 work while " + "going to suspend\n")) + return false; + + return true; +} + +void ieee80211_queue_work(struct ieee80211_hw *hw, struct work_struct *work) +{ + struct ieee80211_local *local = hw_to_local(hw); + + if (!ieee80211_can_queue_work(local)) + return; + + queue_work(local->workqueue, work); +} +EXPORT_SYMBOL(ieee80211_queue_work); + +void ieee80211_queue_delayed_work(struct ieee80211_hw *hw, + struct delayed_work *dwork, + unsigned long delay) +{ + struct ieee80211_local *local = hw_to_local(hw); + + if (!ieee80211_can_queue_work(local)) + return; + + queue_delayed_work(local->workqueue, dwork, delay); +} +EXPORT_SYMBOL(ieee80211_queue_delayed_work); + void ieee802_11_parse_elems(u8 *start, size_t len, struct ieee802_11_elems *elems) { @@ -1114,3 +1154,4 @@ int ieee80211_reconfig(struct ieee80211_local *local) #endif return 0; } + -- cgit v1.2.3 From 056508dcb6890586745aa937e779f00fde05531b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 30 Jul 2009 21:43:55 +0200 Subject: mac80211: fix powersave Some of the recent MLME rework I did broke powersave because the ps_sdata isn't assigned at the right time, and the work item wasn't removed from the list before calling ieee80211_recalc_ps(). To be more specific, this broke the case where you'd enabled PS before associating, either automatically or with iwconfig. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 0779ba150b26..2d5edfda867a 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -916,12 +916,9 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, ieee80211_bss_info_change_notify(sdata, bss_info_changed); - /* will be same as sdata */ - if (local->ps_sdata) { - mutex_lock(&local->iflist_mtx); - ieee80211_recalc_ps(local, -1); - mutex_unlock(&local->iflist_mtx); - } + mutex_lock(&local->iflist_mtx); + ieee80211_recalc_ps(local, -1); + mutex_unlock(&local->iflist_mtx); netif_tx_start_all_queues(sdata->dev); netif_carrier_on(sdata->dev); @@ -1569,6 +1566,9 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, wk->bss->cbss.bssid, ap_ht_cap_flags); + /* delete work item -- must be before set_associated for PS */ + list_del(&wk->list); + /* set AID and assoc capability, * ieee80211_set_associated() will tell the driver */ bss_conf->aid = aid; @@ -1582,7 +1582,6 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); mod_beacon_timer(sdata); - list_del(&wk->list); kfree(wk); return RX_MGMT_CFG80211_ASSOC; } -- cgit v1.2.3 From 8b19e6ca3bac7e04e93fb73f561d670e77c5fae6 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 30 Jul 2009 17:38:09 -0700 Subject: cfg80211: enable country IE support to all cfg80211 drivers Since the bss is always set now once we are connected, if the bss has its own information element we refer to it and pass that instead of relying on mac80211's parsing. Now all cfg80211 drivers get country IE support, automatically and we reduce the call overhead that we had on mac80211 which called this upon every beacon and instead now call this only upon a successfull connection by a STA on cfg80211. Acked-by: Johannes Berg Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2d5edfda867a..c9e4091cd2bb 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1845,12 +1845,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, bssid, ap_ht_cap_flags); } + /* Note: country IE parsing is done for us by cfg80211 */ if (elems.country_elem) { - /* Note we are only reviewing this on beacons - * for the BSSID we are associated to */ - regulatory_hint_11d(local->hw.wiphy, - elems.country_elem, elems.country_elem_len); - /* TODO: IBSS also needs this */ if (elems.pwr_constr_elem) ieee80211_handle_pwr_constr(sdata, -- cgit v1.2.3 From a43abf293965230c93a4b74e5d10b9d60b153ab4 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Fri, 31 Jul 2009 18:54:12 +0300 Subject: mac80211: Retry probe request few times Retry 5 times (chosen arbitary ), before assuming that station is out of range. Fixes frequent disassociations while connected to weak, and sometimes even strong access points. Signed-off-by: Maxim Levitky Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 1 + net/mac80211/mlme.c | 42 ++++++++++++++++++++++++++++++------------ 2 files changed, 31 insertions(+), 12 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 316825be2019..8d790e40f3e9 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -280,6 +280,7 @@ struct ieee80211_if_managed { struct work_struct beacon_loss_work; unsigned long probe_timeout; + int probe_send_count; struct mutex mtx; struct ieee80211_bss *associated; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c9e4091cd2bb..ccd5c7a1749f 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -31,6 +31,7 @@ #define IEEE80211_AUTH_MAX_TRIES 3 #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) #define IEEE80211_ASSOC_MAX_TRIES 3 +#define IEEE80211_MAX_PROBE_TRIES 5 /* * beacon loss detection timeout @@ -1153,11 +1154,24 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME)); } +static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + const u8 *ssid; + + ssid = ieee80211_bss_get_ie(&ifmgd->associated->cbss, WLAN_EID_SSID); + ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid, + ssid + 2, ssid[1], NULL, 0); + + ifmgd->probe_send_count++; + ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT; + run_again(ifmgd, ifmgd->probe_timeout); +} + static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, bool beacon) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - const u8 *ssid; bool already = false; if (!netif_running(sdata->dev)) @@ -1200,18 +1214,12 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, if (already) goto out; - ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT; - mutex_lock(&sdata->local->iflist_mtx); ieee80211_recalc_ps(sdata->local, -1); mutex_unlock(&sdata->local->iflist_mtx); - ssid = ieee80211_bss_get_ie(&ifmgd->associated->cbss, WLAN_EID_SSID); - ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid, - ssid + 2, ssid[1], NULL, 0); - - run_again(ifmgd, ifmgd->probe_timeout); - + ifmgd->probe_send_count = 0; + ieee80211_mgd_probe_ap_send(sdata); out: mutex_unlock(&ifmgd->mtx); } @@ -2064,17 +2072,27 @@ static void ieee80211_sta_work(struct work_struct *work) if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | IEEE80211_STA_CONNECTION_POLL) && ifmgd->associated) { + u8 bssid[ETH_ALEN]; + + memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN); if (time_is_after_jiffies(ifmgd->probe_timeout)) run_again(ifmgd, ifmgd->probe_timeout); - else { - u8 bssid[ETH_ALEN]; + + else if (ifmgd->probe_send_count < IEEE80211_MAX_PROBE_TRIES) { +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + printk(KERN_DEBUG "No probe response from AP %pM" + " after %dms, try %d\n", bssid, + (1000 * IEEE80211_PROBE_WAIT)/HZ, + ifmgd->probe_send_count); +#endif + ieee80211_mgd_probe_ap_send(sdata); + } else { /* * We actually lost the connection ... or did we? * Let's make sure! */ ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | IEEE80211_STA_BEACON_POLL); - memcpy(bssid, ifmgd->associated->cbss.bssid, ETH_ALEN); printk(KERN_DEBUG "No probe response from AP %pM" " after %dms, disconnecting.\n", bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); -- cgit v1.2.3 From d1c5091f23fed5195271e2849f89017d3a126521 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Fri, 31 Jul 2009 18:54:23 +0300 Subject: mac80211: Increase timeouts for station polling Do a probe request every 30 seconds, and wait for probe response, half a second This should lower the traffic that card sends, thus save power Wainting longer for response makes probe more robust against 'slow' access points Signed-off-by: Maxim Levitsky Acked-by: Johannes Berg Tested-by: Marcel Holtmann Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index ccd5c7a1749f..6d5a1ee0445f 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -42,13 +42,13 @@ * Time the connection can be idle before we probe * it to see if we can still talk to the AP. */ -#define IEEE80211_CONNECTION_IDLE_TIME (2 * HZ) +#define IEEE80211_CONNECTION_IDLE_TIME (30 * HZ) /* * Time we wait for a probe response after sending * a probe request because of beacon loss or for * checking the connection still works. */ -#define IEEE80211_PROBE_WAIT (HZ / 5) +#define IEEE80211_PROBE_WAIT (HZ / 2) #define TMR_RUNNING_TIMER 0 #define TMR_RUNNING_CHANSW 1 -- cgit v1.2.3 From e3b90ca28412fb9dcc8c5ca38e179e78fec07eee Mon Sep 17 00:00:00 2001 From: Igor Perminov Date: Tue, 4 Aug 2009 16:48:51 +0400 Subject: mac80211: FIF_PSPOLL filter flag When an interface is configured in the AP mode, the mac80211 implementation doesn't inform the driver to receive PS Poll frames. It leads to inability to communicate with power-saving stations reliably. The FIF_CONTROL flag isn't passed by mac80211 to ieee80211_ops.configure_filter when an interface is in the AP mode. And it's ok, because we don't want to receive ACK frames and other control ones, but only PS Poll ones. This patch introduces the FIF_PSPOLL filter flag in addition to FIF_CONTROL, which means for the driver "pass PS Poll frames". This flag is passed to the driver: A) When an interface is configured in the AP mode. B) In all cases, when the FIF_CONTROL flag was passed earlier (in addition to it). Signed-off-by: Igor Perminov Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/iface.c | 18 ++++++++++++++++-- net/mac80211/main.c | 3 +++ 3 files changed, 20 insertions(+), 3 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 8d790e40f3e9..630a438180fd 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -628,7 +628,7 @@ struct ieee80211_local { int open_count; int monitors, cooked_mntrs; /* number of interfaces with corresponding FIF_ flags */ - int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss; + int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll; unsigned int filter_flags; /* FIF_* */ struct iw_statistics wstats; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 8c1284d45e69..e8fb03b91a44 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -220,8 +220,10 @@ static int ieee80211_open(struct net_device *dev) local->fif_fcsfail++; if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL) local->fif_plcpfail++; - if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) + if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) { local->fif_control++; + local->fif_pspoll++; + } if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) local->fif_other_bss++; @@ -244,7 +246,14 @@ static int ieee80211_open(struct net_device *dev) spin_unlock_bh(&local->filter_lock); ieee80211_start_mesh(sdata); + } else if (sdata->vif.type == NL80211_IFTYPE_AP) { + local->fif_pspoll++; + + spin_lock_bh(&local->filter_lock); + ieee80211_configure_filter(local); + spin_unlock_bh(&local->filter_lock); } + changed |= ieee80211_reset_erp_info(sdata); ieee80211_bss_info_change_notify(sdata, changed); ieee80211_enable_keys(sdata); @@ -388,6 +397,9 @@ static int ieee80211_stop(struct net_device *dev) if (sdata->flags & IEEE80211_SDATA_PROMISC) atomic_dec(&local->iff_promiscs); + if (sdata->vif.type == NL80211_IFTYPE_AP) + local->fif_pspoll--; + netif_addr_lock_bh(dev); spin_lock_bh(&local->filter_lock); __dev_addr_unsync(&local->mc_list, &local->mc_count, @@ -439,8 +451,10 @@ static int ieee80211_stop(struct net_device *dev) local->fif_fcsfail--; if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL) local->fif_plcpfail--; - if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) + if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) { + local->fif_pspoll--; local->fif_control--; + } if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) local->fif_other_bss--; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 22e07385ff60..0c4f8e122ed6 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -77,6 +77,9 @@ void ieee80211_configure_filter(struct ieee80211_local *local) if (local->fif_other_bss) new_flags |= FIF_OTHER_BSS; + if (local->fif_pspoll) + new_flags |= FIF_PSPOLL; + changed_flags = local->filter_flags ^ new_flags; /* be a bit nasty */ -- cgit v1.2.3 From c03e20fc9a6ec5741d9df561130ecba38ef50eb6 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 4 Aug 2009 15:06:26 -0700 Subject: mac80211: fix compilation of mesh (although its disabled) Mesh is currently disabled on mac80211, its marked as broken. This patch gets it to compile though, to account for the mac80211 workqueue changes. There was a simple typo in the patches for mesh for the workqueue migration, but we never compile tested it as we couldn't even select mesh as its broken. Lets at least let it compile for those interested in getting it fixed. Reported-by: Pat Erley Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/mac80211/mesh.c | 10 +++++----- net/mac80211/mesh_hwmp.c | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 2f4f518ab45c..8c068e215fb8 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -54,7 +54,7 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data) return; } - ieee80211_queue_work(local->hw.workqueue, &ifmsh->work); + ieee80211_queue_work(&local->hw, &ifmsh->work); } /** @@ -357,7 +357,7 @@ static void ieee80211_mesh_path_timer(unsigned long data) return; } - ieee80211_queue_work(local->hw.workqueue, &ifmsh->work); + ieee80211_queue_work(&local->hw, &ifmsh->work); } struct mesh_table *mesh_table_grow(struct mesh_table *tbl) @@ -471,7 +471,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) struct ieee80211_local *local = sdata->local; ifmsh->housekeeping = true; - ieee80211_queue_work(local->hw.workqueue, &ifmsh->work); + ieee80211_queue_work(&local->hw, &ifmsh->work); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED); } @@ -619,7 +619,7 @@ void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) if (ieee80211_vif_is_mesh(&sdata->vif)) - ieee80211_queue_work(local->hw.workqueue, &sdata->u.mesh.work); + ieee80211_queue_work(&local->hw, &sdata->u.mesh.work); rcu_read_unlock(); } @@ -692,7 +692,7 @@ ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) case IEEE80211_STYPE_PROBE_RESP: case IEEE80211_STYPE_BEACON: skb_queue_tail(&ifmsh->skb_queue, skb); - ieee80211_queue_work(local->hw.workqueue, &ifmsh->work); + ieee80211_queue_work(&local->hw, &ifmsh->work); return RX_QUEUED; } diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 11ab71a68ff9..e1a763ea1e39 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -660,14 +660,14 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags) spin_unlock(&ifmsh->mesh_preq_queue_lock); if (time_after(jiffies, ifmsh->last_preq + min_preq_int_jiff(sdata))) - ieee80211_queue_work(sdata->local->hw.workqueue, &ifmsh->work); + ieee80211_queue_work(&sdata->local->hw, &ifmsh->work); else if (time_before(jiffies, ifmsh->last_preq)) { /* avoid long wait if did not send preqs for a long time * and jiffies wrapped around */ ifmsh->last_preq = jiffies - min_preq_int_jiff(sdata) - 1; - ieee80211_queue_work(sdata->local->hw.workqueue, &ifmsh->work); + ieee80211_queue_work(&sdata->local->hw, &ifmsh->work); } else mod_timer(&ifmsh->mesh_path_timer, ifmsh->last_preq + min_preq_int_jiff(sdata)); -- cgit v1.2.3 From e21546a2a3953a7d4b9d5c9b1cf12184ffceab96 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 6 Aug 2009 20:41:32 +0200 Subject: mac80211: stay authenticated after disassoc After being disassociated by the AP, mac80211 currently reports this to cfg80211, and then goes to delete the association. That's fine, but cfg80211 assumes that it's still authenticated, however, mac80211 throws away all state. This fixes mac80211 to keep track of the authentication in that case so that cfg80211 can request a deauth or new association properly. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 1 + net/mac80211/mlme.c | 31 ++++++++++++++++++++++--------- 2 files changed, 23 insertions(+), 9 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 630a438180fd..989591787aee 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -284,6 +284,7 @@ struct ieee80211_if_managed { struct mutex mtx; struct ieee80211_bss *associated; + struct ieee80211_mgd_work *old_associate_work; struct list_head work_list; u8 bssid[ETH_ALEN]; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 6d5a1ee0445f..c374d2d73fa4 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -880,10 +880,11 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, } static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, - struct ieee80211_bss *bss, + struct ieee80211_mgd_work *wk, u32 bss_info_changed) { struct ieee80211_local *local = sdata->local; + struct ieee80211_bss *bss = wk->bss; bss_info_changed |= BSS_CHANGED_ASSOC; /* set timing information */ @@ -896,6 +897,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, bss->cbss.capability, bss->has_erp_value, bss->erp_value); sdata->u.mgd.associated = bss; + sdata->u.mgd.old_associate_work = wk; memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN); /* just to be sure */ @@ -1010,7 +1012,8 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, return RX_MGMT_NONE; } -static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) +static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, + bool deauth) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; @@ -1028,6 +1031,16 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) ifmgd->associated = NULL; memset(ifmgd->bssid, 0, ETH_ALEN); + if (deauth) { + kfree(ifmgd->old_associate_work); + ifmgd->old_associate_work = NULL; + } else { + struct ieee80211_mgd_work *wk = ifmgd->old_associate_work; + + wk->state = IEEE80211_MGD_STATE_IDLE; + list_add(&wk->list, &ifmgd->work_list); + } + /* * we need to commit the associated = NULL change because the * scan code uses that to determine whether this iface should @@ -1345,7 +1358,7 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, sdata->dev->name, bssid, reason_code); if (!wk) { - ieee80211_set_disassoc(sdata); + ieee80211_set_disassoc(sdata, true); } else { list_del(&wk->list); kfree(wk); @@ -1378,7 +1391,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", sdata->dev->name, reason_code); - ieee80211_set_disassoc(sdata); + ieee80211_set_disassoc(sdata, false); return RX_MGMT_CFG80211_DISASSOC; } @@ -1581,7 +1594,8 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, * ieee80211_set_associated() will tell the driver */ bss_conf->aid = aid; bss_conf->assoc_capability = capab_info; - ieee80211_set_associated(sdata, wk->bss, changed); + /* this will take ownership of wk */ + ieee80211_set_associated(sdata, wk, changed); /* * Start timer to probe the connection to the AP now. @@ -1590,7 +1604,6 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); mod_beacon_timer(sdata); - kfree(wk); return RX_MGMT_CFG80211_ASSOC; } @@ -2096,7 +2109,7 @@ static void ieee80211_sta_work(struct work_struct *work) printk(KERN_DEBUG "No probe response from AP %pM" " after %dms, disconnecting.\n", bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); - ieee80211_set_disassoc(sdata); + ieee80211_set_disassoc(sdata, true); mutex_unlock(&ifmgd->mtx); /* * must be outside lock due to cfg80211, @@ -2500,7 +2513,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) { bssid = req->bss->bssid; - ieee80211_set_disassoc(sdata); + ieee80211_set_disassoc(sdata, true); } else list_for_each_entry(wk, &ifmgd->work_list, list) { if (&wk->bss->cbss == req->bss) { bssid = req->bss->bssid; @@ -2552,7 +2565,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, return -ENOLINK; } - ieee80211_set_disassoc(sdata); + ieee80211_set_disassoc(sdata, false); mutex_unlock(&ifmgd->mtx); -- cgit v1.2.3 From f5ea9120be2e5d5c846243416cfdce01d02f5836 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 7 Aug 2009 16:17:38 +0200 Subject: nl80211: add generation number to all dumps In order for userspace to be able to figure out whether it obtained a consistent snapshot of data or not when using netlink dumps, we need to have a generation number in each dump message that indicates whether the list has changed or not -- its value is arbitrary. This patch adds such a number to all dumps, this needs some mac80211 involvement to keep track of a generation number to start with when adding/removing mesh paths or stations. The wiphy and netdev lists can be fully handled within cfg80211, of course, but generation numbers need to be stored there as well. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 4 ++++ net/mac80211/ieee80211_i.h | 1 + net/mac80211/mesh.h | 2 ++ net/mac80211/mesh_pathtbl.c | 5 +++++ net/mac80211/sta_info.c | 2 ++ 5 files changed, 14 insertions(+) (limited to 'net/mac80211') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 4bbf5007799b..5608f6c68413 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -323,6 +323,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) { struct ieee80211_sub_if_data *sdata = sta->sdata; + sinfo->generation = sdata->local->sta_generation; + sinfo->filled = STATION_INFO_INACTIVE_TIME | STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES | @@ -909,6 +911,8 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, else memset(next_hop, 0, ETH_ALEN); + pinfo->generation = mesh_paths_generation; + pinfo->filled = MPATH_INFO_FRAME_QLEN | MPATH_INFO_DSN | MPATH_INFO_METRIC | diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 989591787aee..99433222bc5c 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -678,6 +678,7 @@ struct ieee80211_local { struct list_head sta_list; struct sta_info *sta_hash[STA_HASH_SIZE]; struct timer_list sta_cleanup; + int sta_generation; struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; struct tasklet_struct tx_pending_tasklet; diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 2a2ed182cb7e..ce538814b9bd 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -265,6 +265,8 @@ void mesh_path_discard_frame(struct sk_buff *skb, void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata); void mesh_path_restart(struct ieee80211_sub_if_data *sdata); +extern int mesh_paths_generation; + #ifdef CONFIG_MAC80211_MESH extern int mesh_allocated; diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 04b9e4d61b8e..431865a58622 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -38,6 +38,8 @@ struct mpath_node { static struct mesh_table *mesh_paths; static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */ +int mesh_paths_generation; + /* This lock will have the grow table function as writer and add / delete nodes * as readers. When reading the table (i.e. doing lookups) we are well protected * by RCU @@ -243,6 +245,8 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) mesh_paths->mean_chain_len * (mesh_paths->hash_mask + 1)) grow = 1; + mesh_paths_generation++; + spin_unlock(&mesh_paths->hashwlock[hash_idx]); read_unlock(&pathtbl_resize_lock); if (grow) { @@ -484,6 +488,7 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata) err = -ENXIO; enddel: + mesh_paths_generation++; spin_unlock(&mesh_paths->hashwlock[hash_idx]); read_unlock(&pathtbl_resize_lock); return err; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a360bceeba59..eec001491e66 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -349,6 +349,7 @@ int sta_info_insert(struct sta_info *sta) goto out_free; } list_add(&sta->list, &local->sta_list); + local->sta_generation++; local->num_sta++; sta_info_hash_add(local, sta); @@ -485,6 +486,7 @@ static void __sta_info_unlink(struct sta_info **sta) } local->num_sta--; + local->sta_generation++; if (local->ops->sta_notify) { if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) -- cgit v1.2.3 From ad5351db89681515681c5d5659ddf4c69e3cc6f5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 7 Aug 2009 16:42:15 +0200 Subject: mac80211: allow DMA optimisation If we have a lot of frames to transmit at once, for instance with fragmentation, it can be an optimisation to only tell the DMA engine about them on the last fragment/frame to avoid banging the IO too much. This patch allows implementation such an optimisation by telling the driver when more frames can be expected. Currently, this is used by mac80211 only on fragmented frames, but could also be used in the future on other frames when the queue was full and there are multiple frames pending. Note that drivers need to be careful when using this flag, they need to kick their DMA engines not just when this flag is clear, but also when the queue gets full so that progress can be made. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/tx.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net/mac80211') diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 7cffaa046b33..7f2e4cdb8904 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1154,6 +1154,9 @@ static int __ieee80211_tx(struct ieee80211_local *local, next = skb->next; len = skb->len; + if (next) + info->flags |= IEEE80211_TX_CTL_MORE_FRAMES; + sdata = vif_to_sdata(info->control.vif); switch (sdata->vif.type) { -- cgit v1.2.3 From 5ba63533bbf653631faab60f6988506160ec6ba4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 7 Aug 2009 17:54:07 +0200 Subject: cfg80211: fix alignment problem in scan request The memory layout for scan requests was rather wrong, we put the scan SSIDs before the channels which could lead to the channel pointers being unaligned in memory. It turns out that using a pointer to the channel array isn't necessary anyway since we can embed a zero-length array into the struct. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/main.c | 16 ++++++++-------- net/mac80211/scan.c | 10 +++++----- 3 files changed, 14 insertions(+), 14 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 99433222bc5c..d6bd7dd77960 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -715,7 +715,7 @@ struct ieee80211_local { struct mutex scan_mtx; unsigned long scanning; struct cfg80211_ssid scan_ssid; - struct cfg80211_scan_request int_scan_req; + struct cfg80211_scan_request *int_scan_req; struct cfg80211_scan_request *scan_req; struct ieee80211_channel *scan_channel; const u8 *orig_ies; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0c4f8e122ed6..b03fd84777fa 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -765,9 +765,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) supp_ht = supp_ht || sband->ht_cap.ht_supported; } - local->int_scan_req.n_channels = channels; - local->int_scan_req.channels = kzalloc(sizeof(void *) * channels, GFP_KERNEL); - if (!local->int_scan_req.channels) + local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + + sizeof(void *) * channels, GFP_KERNEL); + if (!local->int_scan_req) return -ENOMEM; /* if low-level driver supports AP, we also support VLAN */ @@ -882,13 +882,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) /* alloc internal scan request */ i = 0; - local->int_scan_req.ssids = &local->scan_ssid; - local->int_scan_req.n_ssids = 1; + local->int_scan_req->ssids = &local->scan_ssid; + local->int_scan_req->n_ssids = 1; for (band = 0; band < IEEE80211_NUM_BANDS; band++) { if (!hw->wiphy->bands[band]) continue; for (j = 0; j < hw->wiphy->bands[band]->n_channels; j++) { - local->int_scan_req.channels[i] = + local->int_scan_req->channels[i] = &hw->wiphy->bands[band]->channels[j]; i++; } @@ -920,7 +920,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) fail_workqueue: wiphy_unregister(local->hw.wiphy); fail_wiphy_register: - kfree(local->int_scan_req.channels); + kfree(local->int_scan_req->channels); return result; } EXPORT_SYMBOL(ieee80211_register_hw); @@ -962,7 +962,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) wiphy_unregister(local->hw.wiphy); ieee80211_wep_free(local); ieee80211_led_exit(local); - kfree(local->int_scan_req.channels); + kfree(local->int_scan_req); } EXPORT_SYMBOL(ieee80211_unregister_hw); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 244f53f3c8b4..e091cbc3434f 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -277,7 +277,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) if (test_bit(SCAN_HW_SCANNING, &local->scanning)) ieee80211_restore_scan_ies(local); - if (local->scan_req != &local->int_scan_req) + if (local->scan_req != local->int_scan_req) cfg80211_scan_done(local->scan_req, aborted); local->scan_req = NULL; @@ -423,7 +423,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, local->scan_req = req; local->scan_sdata = sdata; - if (req != &local->int_scan_req && + if (req != local->int_scan_req && sdata->vif.type == NL80211_IFTYPE_STATION && !list_empty(&ifmgd->work_list)) { /* actually wait for the work it's doing to finish/time out */ @@ -743,10 +743,10 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, if (local->scan_req) goto unlock; - memcpy(local->int_scan_req.ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN); - local->int_scan_req.ssids[0].ssid_len = ssid_len; + memcpy(local->int_scan_req->ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN); + local->int_scan_req->ssids[0].ssid_len = ssid_len; - ret = __ieee80211_start_scan(sdata, &sdata->local->int_scan_req); + ret = __ieee80211_start_scan(sdata, sdata->local->int_scan_req); unlock: mutex_unlock(&local->scan_mtx); return ret; -- cgit v1.2.3 From feff1f2fea3fc7ee055e46d0fbdb2d25ad2b14c4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 10 Aug 2009 16:01:54 +0200 Subject: mac80211: take statistics before encryption When encryption is used, the number of bytes sent to the peer increases by the IV and ICV. This is accounted if software encryption is used, but not if the devices does hardware encryption. To make the numbers comparable, never account for that overhead. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/tx.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 7f2e4cdb8904..588c18a60de4 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -843,6 +843,23 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) return TX_CONTINUE; } +static ieee80211_tx_result debug_noinline +ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) +{ + struct sk_buff *skb = tx->skb; + + if (!tx->sta) + return TX_CONTINUE; + + tx->sta->tx_packets++; + do { + tx->sta->tx_fragments++; + tx->sta->tx_bytes += skb->len; + } while ((skb = skb->next)); + + return TX_CONTINUE; +} + static ieee80211_tx_result debug_noinline ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) { @@ -887,23 +904,6 @@ ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx) return TX_CONTINUE; } -static ieee80211_tx_result debug_noinline -ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) -{ - struct sk_buff *skb = tx->skb; - - if (!tx->sta) - return TX_CONTINUE; - - tx->sta->tx_packets++; - do { - tx->sta->tx_fragments++; - tx->sta->tx_bytes += skb->len; - } while ((skb = skb->next)); - - return TX_CONTINUE; -} - /* actual transmit path */ /* @@ -1213,9 +1213,9 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) CALL_TXH(ieee80211_tx_h_sequence) CALL_TXH(ieee80211_tx_h_fragment) /* handlers after fragment must be aware of tx info fragmentation! */ + CALL_TXH(ieee80211_tx_h_stats) CALL_TXH(ieee80211_tx_h_encrypt) CALL_TXH(ieee80211_tx_h_calculate_duration) - CALL_TXH(ieee80211_tx_h_stats) #undef CALL_TXH txh_done: -- cgit v1.2.3 From d0b69609dc50b6bf2637cf74e6f97c251adc65ed Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 10 Aug 2009 16:02:40 +0200 Subject: mac80211: sequence number micro-optimisation There's no need to mask the variable with 0xFFF0 since we ever only use it as a u16 and the lowest four bits can't ever be non-zero. The compiler cannot infer the latter, and therefore has to emit code to do the masking. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/tx.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 588c18a60de4..0c24a4b14505 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -700,7 +700,6 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) /* for pure STA mode without beacons, we can do it */ hdr->seq_ctrl = cpu_to_le16(tx->sdata->sequence_number); tx->sdata->sequence_number += 0x10; - tx->sdata->sequence_number &= IEEE80211_SCTL_SEQ; return TX_CONTINUE; } -- cgit v1.2.3 From 62b1208e146af048e90a32bc4fe5fba85e4fa51e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 10 Aug 2009 16:04:15 +0200 Subject: mac80211: small tx code cleanup It's really easier to read if it's not indented as much, so invert the condition and rearrange the code so the smaller chunk is indented instead. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/tx.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 0c24a4b14505..32442980cc24 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -317,30 +317,30 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) if (!atomic_read(&tx->sdata->bss->num_sta_ps)) return TX_CONTINUE; + /* buffered in hardware */ + if (!(tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING)) { + info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; + + return TX_CONTINUE; + } + /* buffered in mac80211 */ - if (tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) { - if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) - purge_old_ps_buffers(tx->local); - if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= - AP_MAX_BC_BUFFER) { + if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) + purge_old_ps_buffers(tx->local); + + if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= AP_MAX_BC_BUFFER) { #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: BC TX buffer full - " - "dropping the oldest frame\n", - tx->dev->name); - } + if (net_ratelimit()) + printk(KERN_DEBUG "%s: BC TX buffer full - dropping the oldest frame\n", + tx->dev->name); #endif - dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf)); - } else - tx->local->total_ps_buffered++; - skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb); - return TX_QUEUED; - } + dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf)); + } else + tx->local->total_ps_buffered++; - /* buffered in hardware */ - info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; + skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb); - return TX_CONTINUE; + return TX_QUEUED; } static int ieee80211_use_mfp(__le16 fc, struct sta_info *sta, -- cgit v1.2.3 From fe58343461def0d376908a80cebd087b746a1483 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Mon, 10 Aug 2009 12:15:46 -0700 Subject: mac80211: Improve dequeing from mpath frame queue. Also, fix typo in comment. Signed-off-by: Javier Cardona Tested-by: Andrey Yurovsky Signed-off-by: John W. Linville --- net/mac80211/mesh.h | 2 +- net/mac80211/mesh_hwmp.c | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index ce538814b9bd..6aaf1ecbcb63 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -61,7 +61,7 @@ enum mesh_path_flags { * retry * @discovery_retries: number of discovery retries * @flags: mesh path flags, as specified on &enum mesh_path_flags - * @state_lock: mesh pat state lock + * @state_lock: mesh path state lock * * * The combination of dst and sdata is unique in the mesh path table. Since the diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index e1a763ea1e39..b54c21cf5f73 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -810,10 +810,8 @@ int mesh_nexthop_lookup(struct sk_buff *skb, } if (skb_queue_len(&mpath->frame_queue) >= - MESH_FRAME_QUEUE_LEN) { - skb_to_free = mpath->frame_queue.next; - skb_unlink(skb_to_free, &mpath->frame_queue); - } + MESH_FRAME_QUEUE_LEN) + skb_to_free = skb_dequeue(&mpath->frame_queue); info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; skb_queue_tail(&mpath->frame_queue, skb); -- cgit v1.2.3 From a9e3091bf08ddea35f172549a8a21d5bd6ee6129 Mon Sep 17 00:00:00 2001 From: Andrey Yurovsky Date: Mon, 10 Aug 2009 12:15:47 -0700 Subject: mac80211: Use correct sign for mesh active path refresh. On locally originated traffic, we refresh active paths after a timeout. The decision to do this was using the wrong sign and therefore the refresh timer was triggered for every frame. Signed-off-by: Andrey Yurovsky Signed-off-by: Javier Cardona Signed-off-by: John W. Linville --- net/mac80211/mesh_hwmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index b54c21cf5f73..1cd1e7273085 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -791,7 +791,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb, } if (mpath->flags & MESH_PATH_ACTIVE) { - if (time_after(jiffies, mpath->exp_time - + if (time_after(jiffies, mpath->exp_time + msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) && !memcmp(sdata->dev->dev_addr, hdr->addr4, ETH_ALEN) -- cgit v1.2.3 From 3c5772a5279de9eadfff7adb5ddea08106495fff Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Mon, 10 Aug 2009 12:15:48 -0700 Subject: mac80211: Use 3-address format for mesh broadcast frames. The 11s task group recently changed the frame mesh multicast/broadcast frame format to use 3-address. This was done to avoid interactions with widely deployed lazy-WDS access points. This patch changes the format of group addressed frames, both mesh-originated and proxied, to use the data format defined in draft D2.08 and forward. The address fields used for group addressed frames is: In 802.11 header ToDS:0 FromDS:1 addr1: DA (broadcast/multicast address) addr2: TA addr3: Mesh SA In address extension header: addr4: SA (only present if frame was proxied) Note that this change breaks backward compatibility with earlier mesh stack versions. Signed-off-by: Andrey Yurovsky Signed-off-by: Javier Cardona Signed-off-by: John W. Linville --- net/mac80211/mesh.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++---- net/mac80211/mesh.h | 5 ++++- net/mac80211/rx.c | 45 +++++++++++++++++++++++-------------- net/mac80211/tx.c | 64 ++++++++++++++++++++++++++++------------------------- 4 files changed, 124 insertions(+), 52 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 8c068e215fb8..10d93386042a 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -398,22 +398,76 @@ endgrow: return NULL; } +/** + * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame + * @hdr: 802.11 frame header + * @fc: frame control field + * @meshda: destination address in the mesh + * @meshsa: source address address in the mesh. Same as TA, as frame is + * locally originated. + * + * Return the length of the 802.11 (does not include a mesh control header) + */ +int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, char + *meshda, char *meshsa) { + if (is_multicast_ether_addr(meshda)) { + *fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); + /* DA TA SA */ + memcpy(hdr->addr1, meshda, ETH_ALEN); + memcpy(hdr->addr2, meshsa, ETH_ALEN); + memcpy(hdr->addr3, meshsa, ETH_ALEN); + return 24; + } else { + *fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | + IEEE80211_FCTL_TODS); + /* RA TA DA SA */ + memset(hdr->addr1, 0, ETH_ALEN); /* RA is resolved later */ + memcpy(hdr->addr2, meshsa, ETH_ALEN); + memcpy(hdr->addr3, meshda, ETH_ALEN); + memcpy(hdr->addr4, meshsa, ETH_ALEN); + return 30; + } +} + /** * ieee80211_new_mesh_header - create a new mesh header * @meshhdr: uninitialized mesh header * @sdata: mesh interface to be used + * @addr4: addr4 of the mesh frame (1st in ae header) + * may be NULL + * @addr5: addr5 of the mesh frame (1st or 2nd in ae header) + * may be NULL unless addr6 is present + * @addr6: addr6 of the mesh frame (2nd or 3rd in ae header) + * may be NULL unless addr5 is present * * Return the header length. */ int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, - struct ieee80211_sub_if_data *sdata) + struct ieee80211_sub_if_data *sdata, char *addr4, + char *addr5, char *addr6) { - meshhdr->flags = 0; + int aelen = 0; + memset(meshhdr, 0, sizeof(meshhdr)); meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum); sdata->u.mesh.mesh_seqnum++; - - return 6; + if (addr4) { + meshhdr->flags |= MESH_FLAGS_AE_A4; + aelen += ETH_ALEN; + memcpy(meshhdr->eaddr1, addr4, ETH_ALEN); + } + if (addr5 && addr6) { + meshhdr->flags |= MESH_FLAGS_AE_A5_A6; + aelen += 2 * ETH_ALEN; + if (!addr4) { + memcpy(meshhdr->eaddr1, addr5, ETH_ALEN); + memcpy(meshhdr->eaddr2, addr6, ETH_ALEN); + } else { + memcpy(meshhdr->eaddr2, addr5, ETH_ALEN); + memcpy(meshhdr->eaddr3, addr6, ETH_ALEN); + } + } + return 6 + aelen; } static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 6aaf1ecbcb63..2ebd74cb0380 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -193,8 +193,11 @@ struct mesh_rmc { /* Public interfaces */ /* Various */ +int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, + char *da, char *sa); int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, - struct ieee80211_sub_if_data *sdata); + struct ieee80211_sub_if_data *sdata, char *addr4, + char *addr5, char *addr6); int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr, struct ieee80211_sub_if_data *sdata); bool mesh_matches_local(struct ieee802_11_elems *ie, diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 25a669c86e14..4cd9e45b1443 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -489,12 +489,21 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control); + char *dev_addr = rx->dev->dev_addr; if (ieee80211_is_data(hdr->frame_control)) { - if (!ieee80211_has_a4(hdr->frame_control)) - return RX_DROP_MONITOR; - if (memcmp(hdr->addr4, rx->dev->dev_addr, ETH_ALEN) == 0) - return RX_DROP_MONITOR; + if (is_multicast_ether_addr(hdr->addr1)) { + if (ieee80211_has_tods(hdr->frame_control) || + !ieee80211_has_fromds(hdr->frame_control)) + return RX_DROP_MONITOR; + if (memcmp(hdr->addr3, dev_addr, ETH_ALEN) == 0) + return RX_DROP_MONITOR; + } else { + if (!ieee80211_has_a4(hdr->frame_control)) + return RX_DROP_MONITOR; + if (memcmp(hdr->addr4, dev_addr, ETH_ALEN) == 0) + return RX_DROP_MONITOR; + } } /* If there is not an established peer link and this is not a peer link @@ -527,7 +536,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) if (ieee80211_is_data(hdr->frame_control) && is_multicast_ether_addr(hdr->addr1) && - mesh_rmc_check(hdr->addr4, msh_h_get(hdr, hdrlen), rx->sdata)) + mesh_rmc_check(hdr->addr3, msh_h_get(hdr, hdrlen), rx->sdata)) return RX_DROP_MONITOR; #undef msh_h_get @@ -1495,7 +1504,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) /* illegal frame */ return RX_DROP_MONITOR; - if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6){ + if (!is_multicast_ether_addr(hdr->addr1) && + (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6)) { struct mesh_path *mppath; rcu_read_lock(); @@ -1512,7 +1522,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) rcu_read_unlock(); } - if (compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0) + /* Frame has reached destination. Don't forward */ + if (!is_multicast_ether_addr(hdr->addr1) && + compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0) return RX_CONTINUE; mesh_hdr->ttl--; @@ -1532,22 +1544,21 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) rx->dev->name); fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data; - /* - * Save TA to addr1 to send TA a path error if a - * suitable next hop is not found - */ - memcpy(fwd_hdr->addr1, fwd_hdr->addr2, ETH_ALEN); memcpy(fwd_hdr->addr2, rx->dev->dev_addr, ETH_ALEN); info = IEEE80211_SKB_CB(fwd_skb); memset(info, 0, sizeof(*info)); info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; info->control.vif = &rx->sdata->vif; ieee80211_select_queue(local, fwd_skb); - if (is_multicast_ether_addr(fwd_hdr->addr3)) - memcpy(fwd_hdr->addr1, fwd_hdr->addr3, + if (!is_multicast_ether_addr(fwd_hdr->addr1)) { + int err; + /* + * Save TA to addr1 to send TA a path error if a + * suitable next hop is not found + */ + memcpy(fwd_hdr->addr1, fwd_hdr->addr2, ETH_ALEN); - else { - int err = mesh_nexthop_lookup(fwd_skb, sdata); + err = mesh_nexthop_lookup(fwd_skb, sdata); /* Failed to immediately resolve next hop: * fwded frame was dropped or will be added * later to the pending skb queue. */ @@ -1560,7 +1571,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) } } - if (is_multicast_ether_addr(hdr->addr3) || + if (is_multicast_ether_addr(hdr->addr1) || rx->dev->flags & IFF_PROMISC) return RX_CONTINUE; else diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 32442980cc24..ee8aa76f071a 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1414,9 +1414,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, if (ieee80211_vif_is_mesh(&sdata->vif) && ieee80211_is_data(hdr->frame_control)) { - if (is_multicast_ether_addr(hdr->addr3)) - memcpy(hdr->addr1, hdr->addr3, ETH_ALEN); - else + if (!is_multicast_ether_addr(hdr->addr1)) if (mesh_nexthop_lookup(skb, sdata)) { dev_put(sdata->dev); return; @@ -1619,52 +1617,58 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, break; #ifdef CONFIG_MAC80211_MESH case NL80211_IFTYPE_MESH_POINT: - fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); if (!sdata->u.mesh.mshcfg.dot11MeshTTL) { /* Do not send frames with mesh_ttl == 0 */ sdata->u.mesh.mshstats.dropped_frames_ttl++; ret = NETDEV_TX_OK; goto fail; } - memset(&mesh_hdr, 0, sizeof(mesh_hdr)); if (compare_ether_addr(dev->dev_addr, skb->data + ETH_ALEN) == 0) { - /* RA TA DA SA */ - memset(hdr.addr1, 0, ETH_ALEN); - memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); - memcpy(hdr.addr3, skb->data, ETH_ALEN); - memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); - meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, sdata); + hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, + skb->data, skb->data + ETH_ALEN); + meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, + sdata, NULL, NULL, NULL); } else { /* packet from other interface */ struct mesh_path *mppath; + int is_mesh_mcast = 1; + char *mesh_da; - memset(hdr.addr1, 0, ETH_ALEN); - memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); - memcpy(hdr.addr4, dev->dev_addr, ETH_ALEN); - + rcu_read_lock(); if (is_multicast_ether_addr(skb->data)) - memcpy(hdr.addr3, skb->data, ETH_ALEN); + /* DA TA mSA AE:SA */ + mesh_da = skb->data; else { - rcu_read_lock(); mppath = mpp_path_lookup(skb->data, sdata); - if (mppath) - memcpy(hdr.addr3, mppath->mpp, ETH_ALEN); - else - memset(hdr.addr3, 0xff, ETH_ALEN); - rcu_read_unlock(); + if (mppath) { + /* RA TA mDA mSA AE:DA SA */ + mesh_da = mppath->mpp; + is_mesh_mcast = 0; + } else + /* DA TA mSA AE:SA */ + mesh_da = dev->broadcast; } + hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, + mesh_da, dev->dev_addr); + rcu_read_unlock(); + if (is_mesh_mcast) + meshhdrlen = + ieee80211_new_mesh_header(&mesh_hdr, + sdata, + skb->data + ETH_ALEN, + NULL, + NULL); + else + meshhdrlen = + ieee80211_new_mesh_header(&mesh_hdr, + sdata, + NULL, + skb->data, + skb->data + ETH_ALEN); - mesh_hdr.flags |= MESH_FLAGS_AE_A5_A6; - mesh_hdr.ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; - put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &mesh_hdr.seqnum); - memcpy(mesh_hdr.eaddr1, skb->data, ETH_ALEN); - memcpy(mesh_hdr.eaddr2, skb->data + ETH_ALEN, ETH_ALEN); - sdata->u.mesh.mesh_seqnum++; - meshhdrlen = 18; } - hdrlen = 30; break; #endif case NL80211_IFTYPE_STATION: -- cgit v1.2.3 From d403a1c66ea1fb47ae61921eac278d4154f7ca8a Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Mon, 10 Aug 2009 12:15:49 -0700 Subject: mac80211: Update the station failed frames average when minstrel is used. The fail_avg value is used to compute the mesh metric, and was only being set by the pid rate control module. This fixes the mesh path selection mechanism for cards that use mistrel for rate control. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville --- net/mac80211/rc80211_minstrel.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 7c5142988bbb..3ea9740736a5 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -155,12 +155,16 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, struct sk_buff *skb) { struct minstrel_sta_info *mi = priv_sta; + struct minstrel_priv *mp = (struct minstrel_priv *)priv; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *ar = info->status.rates; + struct ieee80211_local *local = hw_to_local(mp->hw); + struct sta_info *si; int i, ndx; int success; success = !!(info->flags & IEEE80211_TX_STAT_ACK); + si = sta_info_get(local, sta->addr); for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { if (ar[i].idx < 0) @@ -172,8 +176,12 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, mi->r[ndx].attempts += ar[i].count; - if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) + if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) { mi->r[ndx].success += success; + if (si) + si->fail_avg = (18050 - mi->r[ndx].probability) + / 180; + } } if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && (i >= 0)) -- cgit v1.2.3 From 5815814bfad5b3f88ff58ab90aaf09dd69ab8da2 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Mon, 10 Aug 2009 12:15:50 -0700 Subject: mac80211: Early detection of broken mesh paths when using minstrel. This change triggers a path discovery as soon as the link quality degrades below a certain threshold. This results in a faster path recovery time than by simply relying on the periodic path refresh mechanism to detect broken links. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville --- net/mac80211/rc80211_minstrel.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 3ea9740736a5..007164919e02 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -51,6 +51,7 @@ #include #include #include +#include "mesh.h" #include "rate.h" #include "rc80211_minstrel.h" @@ -178,9 +179,14 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) { mi->r[ndx].success += success; - if (si) + if (si) { si->fail_avg = (18050 - mi->r[ndx].probability) / 180; + WARN_ON(si->fail_avg > 100); + if (si->fail_avg == 100 && + ieee80211_vif_is_mesh(&si->sdata->vif)) + mesh_plink_broken(si); + } } } -- cgit v1.2.3 From 5b365834255d7c90fc724b032c814dfa297aacf9 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Mon, 10 Aug 2009 12:15:51 -0700 Subject: mac80211: Assign a default mesh beaconing interval. The mesh stack was enabling beaconing without specifying an interval. This patch defines a default beaconing interval of 1s. Incidentally, this fixes mesh beaconing in mac80211_hwsim devices. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville --- net/mac80211/mesh.c | 6 ++++-- net/mac80211/mesh.h | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 10d93386042a..25d0065778ef 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -525,9 +525,11 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) struct ieee80211_local *local = sdata->local; ifmsh->housekeeping = true; - ieee80211_queue_work(&local->hw, &ifmsh->work); + queue_work(local->hw, &ifmsh->work); + sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | - BSS_CHANGED_BEACON_ENABLED); + BSS_CHANGED_BEACON_ENABLED | + BSS_CHANGED_BEACON_INT); } void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 2ebd74cb0380..4241925095c7 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -174,6 +174,7 @@ struct mesh_rmc { */ #define MESH_PATH_REFRESH_TIME 1000 #define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME) +#define MESH_DEFAULT_BEACON_INTERVAL 1000 /* in 1024 us units */ #define MESH_MAX_PREQ_RETRIES 4 #define MESH_PATH_EXPIRE (600 * HZ) -- cgit v1.2.3 From 18889231e4527dfe23145efe318e74744794a95d Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Mon, 10 Aug 2009 12:15:52 -0700 Subject: mac80211: Move mpath and mpp growth to mesh workqueue. This prevents calling rcu_synchronize from within the tx path by moving the table growth code to the mesh workqueue. Move mesh_table_free and mesh_table_grow from mesh.c to mesh_pathtbl.c and declare them static. Also, re-enable mesh in Kconfig and update the configuration description. Signed-off-by: Javier Cardona Tested-by: Andrey Yurovsky Signed-off-by: John W. Linville --- net/mac80211/Kconfig | 8 +-- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/mesh.c | 77 +++-------------------- net/mac80211/mesh.h | 20 +++++- net/mac80211/mesh_pathtbl.c | 146 +++++++++++++++++++++++++++++++++----------- 5 files changed, 144 insertions(+), 109 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 7dd77b6d4c9a..9db4ff836a3d 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -66,12 +66,12 @@ endmenu config MAC80211_MESH bool "Enable mac80211 mesh networking (pre-802.11s) support" depends on MAC80211 && EXPERIMENTAL - depends on BROKEN ---help--- This options enables support of Draft 802.11s mesh networking. - The implementation is based on Draft 1.08 of the Mesh Networking - amendment. For more information visit http://o11s.org/. - + The implementation is based on Draft 2.08 of the Mesh Networking + amendment. However, no compliance with that draft is claimed or even + possible, as drafts leave a number of identifiers to be defined after + ratification. For more information visit http://o11s.org/. config MAC80211_LEDS bool "Enable LED triggers" diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index d6bd7dd77960..a6abc7dfd903 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -355,7 +355,7 @@ struct ieee80211_if_mesh { unsigned long timers_running; - bool housekeeping; + unsigned long wrkq_flags; u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN]; size_t mesh_id_len; diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 25d0065778ef..3185e18c8214 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -47,7 +47,7 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data) struct ieee80211_local *local = sdata->local; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; - ifmsh->housekeeping = true; + ifmsh->wrkq_flags |= MESH_WORK_HOUSEKEEPING; if (local->quiescing) { set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); @@ -320,30 +320,6 @@ struct mesh_table *mesh_table_alloc(int size_order) return newtbl; } -static void __mesh_table_free(struct mesh_table *tbl) -{ - kfree(tbl->hash_buckets); - kfree(tbl->hashwlock); - kfree(tbl); -} - -void mesh_table_free(struct mesh_table *tbl, bool free_leafs) -{ - struct hlist_head *mesh_hash; - struct hlist_node *p, *q; - int i; - - mesh_hash = tbl->hash_buckets; - for (i = 0; i <= tbl->hash_mask; i++) { - spin_lock(&tbl->hashwlock[i]); - hlist_for_each_safe(p, q, &mesh_hash[i]) { - tbl->free_node(p, free_leafs); - atomic_dec(&tbl->entries); - } - spin_unlock(&tbl->hashwlock[i]); - } - __mesh_table_free(tbl); -} static void ieee80211_mesh_path_timer(unsigned long data) { @@ -360,44 +336,6 @@ static void ieee80211_mesh_path_timer(unsigned long data) ieee80211_queue_work(&local->hw, &ifmsh->work); } -struct mesh_table *mesh_table_grow(struct mesh_table *tbl) -{ - struct mesh_table *newtbl; - struct hlist_head *oldhash; - struct hlist_node *p, *q; - int i; - - if (atomic_read(&tbl->entries) - < tbl->mean_chain_len * (tbl->hash_mask + 1)) - goto endgrow; - - newtbl = mesh_table_alloc(tbl->size_order + 1); - if (!newtbl) - goto endgrow; - - newtbl->free_node = tbl->free_node; - newtbl->mean_chain_len = tbl->mean_chain_len; - newtbl->copy_node = tbl->copy_node; - atomic_set(&newtbl->entries, atomic_read(&tbl->entries)); - - oldhash = tbl->hash_buckets; - for (i = 0; i <= tbl->hash_mask; i++) - hlist_for_each(p, &oldhash[i]) - if (tbl->copy_node(p, newtbl) < 0) - goto errcopy; - - return newtbl; - -errcopy: - for (i = 0; i <= newtbl->hash_mask; i++) { - hlist_for_each_safe(p, q, &newtbl->hash_buckets[i]) - tbl->free_node(p, 0); - } - __mesh_table_free(newtbl); -endgrow: - return NULL; -} - /** * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame * @hdr: 802.11 frame header @@ -487,7 +425,6 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, if (free_plinks != sdata->u.mesh.accepting_plinks) ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); - ifmsh->housekeeping = false; mod_timer(&ifmsh->housekeeping_timer, round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); } @@ -524,8 +461,8 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee80211_local *local = sdata->local; - ifmsh->housekeeping = true; - queue_work(local->hw, &ifmsh->work); + ifmsh->wrkq_flags |= MESH_WORK_HOUSEKEEPING; + ieee80211_queue_work(&local->hw, &ifmsh->work); sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED | @@ -664,7 +601,13 @@ static void ieee80211_mesh_work(struct work_struct *work) ifmsh->last_preq + msecs_to_jiffies(ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval))) mesh_path_start_discovery(sdata); - if (ifmsh->housekeeping) + if (test_and_clear_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags)) + mesh_mpath_table_grow(); + + if (test_and_clear_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags)) + mesh_mpp_table_grow(); + + if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags)) ieee80211_mesh_housekeeping(sdata, ifmsh); } diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 4241925095c7..eb23fc639b2b 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -43,6 +43,23 @@ enum mesh_path_flags { MESH_PATH_RESOLVED = BIT(4), }; +/** + * enum mesh_deferred_task_flags - mac80211 mesh deferred tasks + * + * + * + * @MESH_WORK_HOUSEKEEPING: run the periodic mesh housekeeping tasks + * @MESH_WORK_GROW_MPATH_TABLE: the mesh path table is full and needs + * to grow. + * @MESH_WORK_GROW_MPP_TABLE: the mesh portals table is full and needs to + * grow + */ +enum mesh_deferred_task_flags { + MESH_WORK_HOUSEKEEPING, + MESH_WORK_GROW_MPATH_TABLE, + MESH_WORK_GROW_MPP_TABLE, +}; + /** * struct mesh_path - mac80211 mesh path structure * @@ -250,7 +267,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, /* Mesh tables */ struct mesh_table *mesh_table_alloc(int size_order); void mesh_table_free(struct mesh_table *tbl, bool free_leafs); -struct mesh_table *mesh_table_grow(struct mesh_table *tbl); +void mesh_mpath_table_grow(void); +void mesh_mpp_table_grow(void); u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, struct mesh_table *tbl); /* Mesh paths */ diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 431865a58622..751c4d0e2b36 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -39,6 +39,69 @@ static struct mesh_table *mesh_paths; static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */ int mesh_paths_generation; +static void __mesh_table_free(struct mesh_table *tbl) +{ + kfree(tbl->hash_buckets); + kfree(tbl->hashwlock); + kfree(tbl); +} + +void mesh_table_free(struct mesh_table *tbl, bool free_leafs) +{ + struct hlist_head *mesh_hash; + struct hlist_node *p, *q; + int i; + + mesh_hash = tbl->hash_buckets; + for (i = 0; i <= tbl->hash_mask; i++) { + spin_lock(&tbl->hashwlock[i]); + hlist_for_each_safe(p, q, &mesh_hash[i]) { + tbl->free_node(p, free_leafs); + atomic_dec(&tbl->entries); + } + spin_unlock(&tbl->hashwlock[i]); + } + __mesh_table_free(tbl); +} + +static struct mesh_table *mesh_table_grow(struct mesh_table *tbl) +{ + struct mesh_table *newtbl; + struct hlist_head *oldhash; + struct hlist_node *p, *q; + int i; + + if (atomic_read(&tbl->entries) + < tbl->mean_chain_len * (tbl->hash_mask + 1)) + goto endgrow; + + newtbl = mesh_table_alloc(tbl->size_order + 1); + if (!newtbl) + goto endgrow; + + newtbl->free_node = tbl->free_node; + newtbl->mean_chain_len = tbl->mean_chain_len; + newtbl->copy_node = tbl->copy_node; + atomic_set(&newtbl->entries, atomic_read(&tbl->entries)); + + oldhash = tbl->hash_buckets; + for (i = 0; i <= tbl->hash_mask; i++) + hlist_for_each(p, &oldhash[i]) + if (tbl->copy_node(p, newtbl) < 0) + goto errcopy; + + return newtbl; + +errcopy: + for (i = 0; i <= newtbl->hash_mask; i++) { + hlist_for_each_safe(p, q, &newtbl->hash_buckets[i]) + tbl->free_node(p, 0); + } + __mesh_table_free(newtbl); +endgrow: + return NULL; +} + /* This lock will have the grow table function as writer and add / delete nodes * as readers. When reading the table (i.e. doing lookups) we are well protected @@ -187,6 +250,8 @@ struct mesh_path *mesh_path_lookup_by_idx(int idx, struct ieee80211_sub_if_data */ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) { + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; + struct ieee80211_local *local = sdata->local; struct mesh_path *mpath, *new_mpath; struct mpath_node *node, *new_node; struct hlist_head *bucket; @@ -195,8 +260,6 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) int err = 0; u32 hash_idx; - might_sleep(); - if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0) /* never add ourselves as neighbours */ return -ENOTSUPP; @@ -208,11 +271,11 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) return -ENOSPC; err = -ENOMEM; - new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL); + new_mpath = kzalloc(sizeof(struct mesh_path), GFP_ATOMIC); if (!new_mpath) goto err_path_alloc; - new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL); + new_node = kmalloc(sizeof(struct mpath_node), GFP_ATOMIC); if (!new_node) goto err_node_alloc; @@ -250,20 +313,8 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) spin_unlock(&mesh_paths->hashwlock[hash_idx]); read_unlock(&pathtbl_resize_lock); if (grow) { - struct mesh_table *oldtbl, *newtbl; - - write_lock(&pathtbl_resize_lock); - oldtbl = mesh_paths; - newtbl = mesh_table_grow(mesh_paths); - if (!newtbl) { - write_unlock(&pathtbl_resize_lock); - return 0; - } - rcu_assign_pointer(mesh_paths, newtbl); - write_unlock(&pathtbl_resize_lock); - - synchronize_rcu(); - mesh_table_free(oldtbl, false); + set_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags); + ieee80211_queue_work(&local->hw, &ifmsh->work); } return 0; @@ -278,9 +329,46 @@ err_path_alloc: return err; } +void mesh_mpath_table_grow(void) +{ + struct mesh_table *oldtbl, *newtbl; + + write_lock(&pathtbl_resize_lock); + oldtbl = mesh_paths; + newtbl = mesh_table_grow(mesh_paths); + if (!newtbl) { + write_unlock(&pathtbl_resize_lock); + return; + } + rcu_assign_pointer(mesh_paths, newtbl); + write_unlock(&pathtbl_resize_lock); + + synchronize_rcu(); + mesh_table_free(oldtbl, false); +} + +void mesh_mpp_table_grow(void) +{ + struct mesh_table *oldtbl, *newtbl; + + write_lock(&pathtbl_resize_lock); + oldtbl = mpp_paths; + newtbl = mesh_table_grow(mpp_paths); + if (!newtbl) { + write_unlock(&pathtbl_resize_lock); + return; + } + rcu_assign_pointer(mpp_paths, newtbl); + write_unlock(&pathtbl_resize_lock); + + synchronize_rcu(); + mesh_table_free(oldtbl, false); +} int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) { + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; + struct ieee80211_local *local = sdata->local; struct mesh_path *mpath, *new_mpath; struct mpath_node *node, *new_node; struct hlist_head *bucket; @@ -289,8 +377,6 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) int err = 0; u32 hash_idx; - might_sleep(); - if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0) /* never add ourselves as neighbours */ return -ENOTSUPP; @@ -299,11 +385,11 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) return -ENOTSUPP; err = -ENOMEM; - new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL); + new_mpath = kzalloc(sizeof(struct mesh_path), GFP_ATOMIC); if (!new_mpath) goto err_path_alloc; - new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL); + new_node = kmalloc(sizeof(struct mpath_node), GFP_ATOMIC); if (!new_node) goto err_node_alloc; @@ -337,20 +423,8 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) spin_unlock(&mpp_paths->hashwlock[hash_idx]); read_unlock(&pathtbl_resize_lock); if (grow) { - struct mesh_table *oldtbl, *newtbl; - - write_lock(&pathtbl_resize_lock); - oldtbl = mpp_paths; - newtbl = mesh_table_grow(mpp_paths); - if (!newtbl) { - write_unlock(&pathtbl_resize_lock); - return 0; - } - rcu_assign_pointer(mpp_paths, newtbl); - write_unlock(&pathtbl_resize_lock); - - synchronize_rcu(); - mesh_table_free(oldtbl, false); + set_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags); + ieee80211_queue_work(&local->hw, &ifmsh->work); } return 0; -- cgit v1.2.3 From cca89496a8afe4ad12ce1e468e60cef1e27e4eee Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Mon, 10 Aug 2009 17:29:29 -0700 Subject: mac80211: Fix unresolved mesh frames queued without valid control.vif Mesh frames that could not be immediately resolved were queued with a NULL info->control.vif. This patch moves the call to mesh_nexthop_lookup closer to the point where it is handed over to ieee80211_tx(). This ensures that the unresolved frames are ready to be sent once the path is resolved. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville --- net/mac80211/tx.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index ee8aa76f071a..0c08d1e60cb5 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1412,14 +1412,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; - if (ieee80211_vif_is_mesh(&sdata->vif) && - ieee80211_is_data(hdr->frame_control)) { - if (!is_multicast_ether_addr(hdr->addr1)) - if (mesh_nexthop_lookup(skb, sdata)) { - dev_put(sdata->dev); - return; - } - } else if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) { + if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) { int hdrlen; u16 len_rthdr; @@ -1476,6 +1469,15 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, info->control.vif = &sdata->vif; + if (ieee80211_vif_is_mesh(&sdata->vif) && + ieee80211_is_data(hdr->frame_control) && + !is_multicast_ether_addr(hdr->addr1)) + if (mesh_nexthop_lookup(skb, sdata)) { + /* skb queued: don't free */ + dev_put(sdata->dev); + return; + } + ieee80211_select_queue(local, skb); ieee80211_tx(sdata, skb, false); dev_put(sdata->dev); -- cgit v1.2.3 From 57ef5ddb456649667438e023f67dd3a3ff3fbed8 Mon Sep 17 00:00:00 2001 From: David Woo Date: Wed, 12 Aug 2009 11:03:43 -0700 Subject: mac80211: Mark a destination sequence number as valid when a PREQ is received. If a PREQ frame is received giving us a fresher DSN than what we have, record the new dsn and mark it as valid. This patch fixes a bug in the setting of the MESH_PATH_DSN_VALID flag. Also, minor fix to coding style on that file. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville --- net/mac80211/mesh_hwmp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 1cd1e7273085..ef1efd362691 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -397,7 +397,8 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, - u8 *preq_elem, u32 metric) { + u8 *preq_elem, u32 metric) +{ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct mesh_path *mpath; u8 *dst_addr, *orig_addr; @@ -430,7 +431,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, if ((!(mpath->flags & MESH_PATH_DSN_VALID)) || DSN_LT(mpath->dsn, dst_dsn)) { mpath->dsn = dst_dsn; - mpath->flags &= MESH_PATH_DSN_VALID; + mpath->flags |= MESH_PATH_DSN_VALID; } else if ((!(dst_flags & MP_F_DO)) && (mpath->flags & MESH_PATH_ACTIVE)) { reply = true; -- cgit v1.2.3 From 70bdb6b275d789ddf05c3a858e6b57715539394b Mon Sep 17 00:00:00 2001 From: David Woo Date: Wed, 12 Aug 2009 11:03:44 -0700 Subject: mac80211: Fix invalid length passed to IE parser for PLINK CONFIRM frames The length of the fixed portion of plink confirm frames is 4 bytes longer than the other plink_action frames. This path corrects an error in the length adjustment done for these type of frames. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville --- net/mac80211/mesh_plink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index cb14253587f1..ffcbad75e09b 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -409,7 +409,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m baselen = (u8 *) mgmt->u.action.u.plink_action.variable - (u8 *) mgmt; if (mgmt->u.action.u.plink_action.action_code == PLINK_CONFIRM) { baseaddr += 4; - baselen -= 4; + baselen += 4; } ieee802_11_parse_elems(baseaddr, len - baselen, &elems); if (!elems.peer_link) { -- cgit v1.2.3 From 3ac64beecd27400d12cc7afb4108eef26c499f6a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 17 Aug 2009 16:16:53 +0200 Subject: mac80211: allow configure_filter callback to sleep Over time, a whole bunch of drivers have come up with their own scheme to delay the configure_filter operation to a workqueue. To be able to simplify things, allow configure_filter to sleep, and add a new prepare_multicast callback that drivers that need the multicast address list implement. This new callback must be atomic, but most drivers either don't care or just calculate a hash which can be done atomically and then uploaded to the hardware non-atomically. A cursory look suggests that at76c50x-usb, ar9170, mwl8k (which is actually very broken now), rt2x00, wl1251, wl1271 and zd1211 should make use of this new capability. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/driver-ops.h | 24 ++++++++++++++++++++---- net/mac80211/driver-trace.h | 36 ++++++++++++++++++++++++++++++------ net/mac80211/ieee80211_i.h | 3 +++ net/mac80211/iface.c | 15 +++------------ net/mac80211/main.c | 24 +++++++++++++++++++----- net/mac80211/scan.c | 16 ++-------------- net/mac80211/util.c | 2 -- 7 files changed, 77 insertions(+), 43 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 4100c361a99d..d231c9323ad1 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -55,16 +55,32 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local, trace_drv_bss_info_changed(local, vif, info, changed); } +static inline u64 drv_prepare_multicast(struct ieee80211_local *local, + int mc_count, + struct dev_addr_list *mc_list) +{ + u64 ret = 0; + + if (local->ops->prepare_multicast) + ret = local->ops->prepare_multicast(&local->hw, mc_count, + mc_list); + + trace_drv_prepare_multicast(local, mc_count, ret); + + return ret; +} + static inline void drv_configure_filter(struct ieee80211_local *local, unsigned int changed_flags, unsigned int *total_flags, - int mc_count, - struct dev_addr_list *mc_list) + u64 multicast) { + might_sleep(); + local->ops->configure_filter(&local->hw, changed_flags, total_flags, - mc_count, mc_list); + multicast); trace_drv_configure_filter(local, changed_flags, total_flags, - mc_count); + multicast); } static inline int drv_set_tim(struct ieee80211_local *local, diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 5a10da2d70fd..37b9051afcf3 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -191,31 +191,55 @@ TRACE_EVENT(drv_bss_info_changed, ) ); +TRACE_EVENT(drv_prepare_multicast, + TP_PROTO(struct ieee80211_local *local, int mc_count, u64 ret), + + TP_ARGS(local, mc_count, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + __field(int, mc_count) + __field(u64, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + __entry->mc_count = mc_count; + __entry->ret = ret; + ), + + TP_printk( + LOCAL_PR_FMT " prepare mc (%d): %llx", + LOCAL_PR_ARG, __entry->mc_count, + (unsigned long long) __entry->ret + ) +); + TRACE_EVENT(drv_configure_filter, TP_PROTO(struct ieee80211_local *local, unsigned int changed_flags, unsigned int *total_flags, - int mc_count), + u64 multicast), - TP_ARGS(local, changed_flags, total_flags, mc_count), + TP_ARGS(local, changed_flags, total_flags, multicast), TP_STRUCT__entry( LOCAL_ENTRY __field(unsigned int, changed) __field(unsigned int, total) - __field(int, mc) + __field(u64, multicast) ), TP_fast_assign( LOCAL_ASSIGN; __entry->changed = changed_flags; __entry->total = *total_flags; - __entry->mc = mc_count; + __entry->multicast = multicast; ), TP_printk( - LOCAL_PR_FMT " changed:%#x total:%#x mc:%d", - LOCAL_PR_ARG, __entry->changed, __entry->total, __entry->mc + LOCAL_PR_FMT " changed:%#x total:%#x", + LOCAL_PR_ARG, __entry->changed, __entry->total ) ); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a6abc7dfd903..a07f01736a91 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -636,6 +636,9 @@ struct ieee80211_local { /* protects the aggregated multicast list and filter calls */ spinlock_t filter_lock; + /* used for uploading changed mc list */ + struct work_struct reconfig_filter; + /* aggregated multicast list */ struct dev_addr_list *mc_list; int mc_count; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index e8fb03b91a44..b161301056df 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -227,9 +227,7 @@ static int ieee80211_open(struct net_device *dev) if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) local->fif_other_bss++; - spin_lock_bh(&local->filter_lock); ieee80211_configure_filter(local); - spin_unlock_bh(&local->filter_lock); break; default: conf.vif = &sdata->vif; @@ -241,17 +239,13 @@ static int ieee80211_open(struct net_device *dev) if (ieee80211_vif_is_mesh(&sdata->vif)) { local->fif_other_bss++; - spin_lock_bh(&local->filter_lock); ieee80211_configure_filter(local); - spin_unlock_bh(&local->filter_lock); ieee80211_start_mesh(sdata); } else if (sdata->vif.type == NL80211_IFTYPE_AP) { local->fif_pspoll++; - spin_lock_bh(&local->filter_lock); ieee80211_configure_filter(local); - spin_unlock_bh(&local->filter_lock); } changed |= ieee80211_reset_erp_info(sdata); @@ -404,10 +398,11 @@ static int ieee80211_stop(struct net_device *dev) spin_lock_bh(&local->filter_lock); __dev_addr_unsync(&local->mc_list, &local->mc_count, &dev->mc_list, &dev->mc_count); - ieee80211_configure_filter(local); spin_unlock_bh(&local->filter_lock); netif_addr_unlock_bh(dev); + ieee80211_configure_filter(local); + del_timer_sync(&local->dynamic_ps_timer); cancel_work_sync(&local->dynamic_ps_enable_work); @@ -458,9 +453,7 @@ static int ieee80211_stop(struct net_device *dev) if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) local->fif_other_bss--; - spin_lock_bh(&local->filter_lock); ieee80211_configure_filter(local); - spin_unlock_bh(&local->filter_lock); break; case NL80211_IFTYPE_STATION: del_timer_sync(&sdata->u.mgd.chswitch_timer); @@ -503,9 +496,7 @@ static int ieee80211_stop(struct net_device *dev) local->fif_other_bss--; atomic_dec(&local->iff_allmultis); - spin_lock_bh(&local->filter_lock); ieee80211_configure_filter(local); - spin_unlock_bh(&local->filter_lock); ieee80211_stop_mesh(sdata); } @@ -622,8 +613,8 @@ static void ieee80211_set_multicast_list(struct net_device *dev) spin_lock_bh(&local->filter_lock); __dev_addr_sync(&local->mc_list, &local->mc_count, &dev->mc_list, &dev->mc_count); - ieee80211_configure_filter(local); spin_unlock_bh(&local->filter_lock); + ieee80211_queue_work(&local->hw, &local->reconfig_filter); } /* diff --git a/net/mac80211/main.c b/net/mac80211/main.c index b03fd84777fa..05f923575fee 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -50,9 +50,9 @@ struct ieee80211_tx_status_rtap_hdr { } __attribute__ ((packed)); -/* must be called under mdev tx lock */ void ieee80211_configure_filter(struct ieee80211_local *local) { + u64 mc; unsigned int changed_flags; unsigned int new_flags = 0; @@ -62,7 +62,7 @@ void ieee80211_configure_filter(struct ieee80211_local *local) if (atomic_read(&local->iff_allmultis)) new_flags |= FIF_ALLMULTI; - if (local->monitors) + if (local->monitors || local->scanning) new_flags |= FIF_BCN_PRBRESP_PROMISC; if (local->fif_fcsfail) @@ -80,20 +80,30 @@ void ieee80211_configure_filter(struct ieee80211_local *local) if (local->fif_pspoll) new_flags |= FIF_PSPOLL; + spin_lock_bh(&local->filter_lock); changed_flags = local->filter_flags ^ new_flags; + mc = drv_prepare_multicast(local, local->mc_count, local->mc_list); + spin_unlock_bh(&local->filter_lock); + /* be a bit nasty */ new_flags |= (1<<31); - drv_configure_filter(local, changed_flags, &new_flags, - local->mc_count, - local->mc_list); + drv_configure_filter(local, changed_flags, &new_flags, mc); WARN_ON(new_flags & (1<<31)); local->filter_flags = new_flags & ~(1<<31); } +static void ieee80211_reconfig_filter(struct work_struct *work) +{ + struct ieee80211_local *local = + container_of(work, struct ieee80211_local, reconfig_filter); + + ieee80211_configure_filter(local); +} + int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) { struct ieee80211_channel *chan, *scan_chan; @@ -692,6 +702,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, INIT_WORK(&local->restart_work, ieee80211_restart_work); + INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); + INIT_WORK(&local->dynamic_ps_enable_work, ieee80211_dynamic_ps_enable_work); INIT_WORK(&local->dynamic_ps_disable_work, @@ -946,6 +958,8 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) rtnl_unlock(); + cancel_work_sync(&local->reconfig_filter); + ieee80211_clear_tx_pending(local); sta_info_stop(local); rate_control_deinitialize(local); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index e091cbc3434f..1e04be6b9129 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -292,13 +292,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) if (was_hw_scan) goto done; - spin_lock_bh(&local->filter_lock); - local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC; - drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC, - &local->filter_flags, - local->mc_count, - local->mc_list); - spin_unlock_bh(&local->filter_lock); + ieee80211_configure_filter(local); drv_sw_scan_complete(local); @@ -376,13 +370,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) local->next_scan_state = SCAN_DECISION; local->scan_channel_idx = 0; - spin_lock_bh(&local->filter_lock); - local->filter_flags |= FIF_BCN_PRBRESP_PROMISC; - drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC, - &local->filter_flags, - local->mc_count, - local->mc_list); - spin_unlock_bh(&local->filter_lock); + ieee80211_configure_filter(local); /* TODO: start scan as soon as all nullfunc frames are ACKed */ ieee80211_queue_delayed_work(&local->hw, diff --git a/net/mac80211/util.c b/net/mac80211/util.c index e55d57f559ec..5eb306377c63 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1076,9 +1076,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) /* reconfigure hardware */ ieee80211_hw_config(local, ~0); - spin_lock_bh(&local->filter_lock); ieee80211_configure_filter(local); - spin_unlock_bh(&local->filter_lock); /* Finally also reconfigure all the BSS information */ list_for_each_entry(sdata, &local->interfaces, list) { -- cgit v1.2.3 From f424afa17899408cbd267a4c4534ca6fc9d8f71c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 17 Aug 2009 16:18:07 +0200 Subject: mac80211: remove deprecated API All but two drivers have now stopped using the two deprecated members radio_enabled and beacon_int, so it's about time to remove them for good. Signed-off-by: Johannes Berg Acked-by: Kalle Valo Signed-off-by: John W. Linville --- net/mac80211/main.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 05f923575fee..3302df96f8d4 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -241,9 +241,6 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, drv_bss_info_changed(local, &sdata->vif, &sdata->vif.bss_conf, changed); - - /* DEPRECATED */ - local->hw.conf.beacon_int = sdata->vif.bss_conf.beacon_int; } u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) @@ -687,7 +684,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, local->hw.max_rates = 1; local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; - local->hw.conf.radio_enabled = true; local->user_power_level = -1; INIT_LIST_HEAD(&local->interfaces); -- cgit v1.2.3 From bfc32e6a9559d3e30925929cd9a9df7498f325db Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Mon, 17 Aug 2009 17:15:55 -0700 Subject: mac80211: Decouple fail_avg stats used by mesh from rate control algorithm. Mesh uses the tx failure average to compute the (m)path metric. This used to be done inside the rate control module. This patch breaks the dependency between the mesh stack and the rate control algorithm. Mesh will now work independently of the chosen rate control algorithm. The mesh stack keeps a moving average of the average transmission losses for each mesh peer station. If the fail average exceeds a certain threshold, the peer link is marked as broken. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville --- net/mac80211/main.c | 2 ++ net/mac80211/mesh.h | 2 ++ net/mac80211/mesh_hwmp.c | 18 ++++++++++++++++++ net/mac80211/rc80211_minstrel.c | 16 +--------------- net/mac80211/rc80211_pid_algo.c | 15 +-------------- 5 files changed, 24 insertions(+), 29 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 3302df96f8d4..f80efd7ff5ec 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -482,6 +482,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) } rate_control_tx_status(local, sband, sta, skb); + if (ieee80211_vif_is_mesh(&sta->sdata->vif)) + ieee80211s_update_metric(local, sta, skb); } rcu_read_unlock(); diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index eb23fc639b2b..dd1c19319f0a 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -226,6 +226,8 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, void mesh_rmc_free(struct ieee80211_sub_if_data *sdata); int mesh_rmc_init(struct ieee80211_sub_if_data *sdata); void ieee80211s_init(void); +void ieee80211s_update_metric(struct ieee80211_local *local, + struct sta_info *stainfo, struct sk_buff *skb); void ieee80211s_stop(void); void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata); ieee80211_rx_result diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index ef1efd362691..7aeba00ac502 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -201,6 +201,24 @@ int mesh_path_error_tx(u8 *dst, __le32 dst_dsn, u8 *ra, return 0; } +void ieee80211s_update_metric(struct ieee80211_local *local, + struct sta_info *stainfo, struct sk_buff *skb) +{ + struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + int failed; + + if (!ieee80211_is_data(hdr->frame_control)) + return; + + failed = !(txinfo->flags & IEEE80211_TX_STAT_ACK); + + /* moving average, scaled to 100 */ + stainfo->fail_avg = ((80 * stainfo->fail_avg + 5) / 100 + 20 * failed); + if (stainfo->fail_avg > 95) + mesh_plink_broken(stainfo); +} + static u32 airtime_link_metric_get(struct ieee80211_local *local, struct sta_info *sta) { diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 007164919e02..7c5142988bbb 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -51,7 +51,6 @@ #include #include #include -#include "mesh.h" #include "rate.h" #include "rc80211_minstrel.h" @@ -156,16 +155,12 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, struct sk_buff *skb) { struct minstrel_sta_info *mi = priv_sta; - struct minstrel_priv *mp = (struct minstrel_priv *)priv; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *ar = info->status.rates; - struct ieee80211_local *local = hw_to_local(mp->hw); - struct sta_info *si; int i, ndx; int success; success = !!(info->flags & IEEE80211_TX_STAT_ACK); - si = sta_info_get(local, sta->addr); for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { if (ar[i].idx < 0) @@ -177,17 +172,8 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, mi->r[ndx].attempts += ar[i].count; - if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) { + if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) mi->r[ndx].success += success; - if (si) { - si->fail_avg = (18050 - mi->r[ndx].probability) - / 180; - WARN_ON(si->fail_avg > 100); - if (si->fail_avg == 100 && - ieee80211_vif_is_mesh(&si->sdata->vif)) - mesh_plink_broken(si); - } - } } if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && (i >= 0)) diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index 8c053be9dc24..f6e25d7d957c 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -169,19 +169,9 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo, * still a good measurement and copy it. */ if (unlikely(spinfo->tx_num_xmit == 0)) pf = spinfo->last_pf; - else { - /* XXX: BAD HACK!!! */ - struct sta_info *si = container_of(sta, struct sta_info, sta); - + else pf = spinfo->tx_num_failed * 100 / spinfo->tx_num_xmit; - if (ieee80211_vif_is_mesh(&si->sdata->vif) && pf == 100) - mesh_plink_broken(si); - pf <<= RC_PID_ARITH_SHIFT; - si->fail_avg = ((pf + (spinfo->last_pf << 3)) / 9) - >> RC_PID_ARITH_SHIFT; - } - spinfo->tx_num_xmit = 0; spinfo->tx_num_failed = 0; @@ -348,9 +338,6 @@ rate_control_pid_rate_init(void *priv, struct ieee80211_supported_band *sband, } spinfo->txrate_idx = rate_lowest_index(sband, sta); - /* HACK */ - si = container_of(sta, struct sta_info, sta); - si->fail_avg = 0; } static void *rate_control_pid_alloc(struct ieee80211_hw *hw, -- cgit v1.2.3 From 29508d122a5228c2a68d1e9a39251d3991b3cfef Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 18 Aug 2009 10:46:42 -0400 Subject: rc80211_pid_algo.c: remove unused variable declaration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CC [M] net/mac80211/rc80211_pid_algo.o net/mac80211/rc80211_pid_algo.c: In function ‘rate_control_pid_rate_init’: net/mac80211/rc80211_pid_algo.c:304: warning: unused variable ‘si’ Signed-off-by: John W. Linville --- net/mac80211/rc80211_pid_algo.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index f6e25d7d957c..699d3ed869c4 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -301,7 +301,6 @@ rate_control_pid_rate_init(void *priv, struct ieee80211_supported_band *sband, struct rc_pid_sta_info *spinfo = priv_sta; struct rc_pid_info *pinfo = priv; struct rc_pid_rateinfo *rinfo = pinfo->rinfo; - struct sta_info *si; int i, j, tmp; bool s; -- cgit v1.2.3 From c8a61a7d33350eeec668fc6230ad55f5fa93209b Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Tue, 18 Aug 2009 10:59:00 -0700 Subject: mac80211: New stat counters for multicast and unicast forwarded frames This expands on the current fwded_frames stat counter which should be equal to the total of these two new counters. The new counters are called "fwded_mcast" and "fwded_unicast". Signed-off-by: Daniel Walker Signed-off-by: Javier Cardona Signed-off-by: John W. Linville --- net/mac80211/debugfs_netdev.c | 6 ++++++ net/mac80211/ieee80211_i.h | 6 +++++- net/mac80211/mesh_hwmp.c | 3 +++ net/mac80211/rx.c | 8 +++++++- 4 files changed, 21 insertions(+), 2 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index e9ec6cae2d39..61234e79022b 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -116,6 +116,8 @@ IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); #ifdef CONFIG_MAC80211_MESH /* Mesh stats attributes */ +IEEE80211_IF_FILE(fwded_mcast, u.mesh.mshstats.fwded_mcast, DEC); +IEEE80211_IF_FILE(fwded_unicast, u.mesh.mshstats.fwded_unicast, DEC); IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC); IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC); IEEE80211_IF_FILE(dropped_frames_no_route, @@ -205,6 +207,8 @@ static void add_mesh_stats(struct ieee80211_sub_if_data *sdata) { sdata->mesh_stats_dir = debugfs_create_dir("mesh_stats", sdata->debugfsdir); + MESHSTATS_ADD(fwded_mcast); + MESHSTATS_ADD(fwded_unicast); MESHSTATS_ADD(fwded_frames); MESHSTATS_ADD(dropped_frames_ttl); MESHSTATS_ADD(dropped_frames_no_route); @@ -327,6 +331,8 @@ static void del_monitor_files(struct ieee80211_sub_if_data *sdata) static void del_mesh_stats(struct ieee80211_sub_if_data *sdata) { + MESHSTATS_DEL(fwded_mcast); + MESHSTATS_DEL(fwded_unicast); MESHSTATS_DEL(fwded_frames); MESHSTATS_DEL(dropped_frames_ttl); MESHSTATS_DEL(dropped_frames_no_route); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a07f01736a91..93e618a980d1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -212,7 +212,9 @@ struct ieee80211_if_vlan { }; struct mesh_stats { - __u32 fwded_frames; /* Mesh forwarded frames */ + __u32 fwded_mcast; /* Mesh forwarded multicast frames */ + __u32 fwded_unicast; /* Mesh forwarded unicast frames */ + __u32 fwded_frames; /* Mesh total forwarded frames */ __u32 dropped_frames_ttl; /* Not transmitted since mesh_ttl == 0*/ __u32 dropped_frames_no_route; /* Not transmitted, no route found */ atomic_t estab_plinks; @@ -506,6 +508,8 @@ struct ieee80211_sub_if_data { #ifdef CONFIG_MAC80211_MESH struct dentry *mesh_stats_dir; struct { + struct dentry *fwded_mcast; + struct dentry *fwded_unicast; struct dentry *fwded_frames; struct dentry *dropped_frames_ttl; struct dentry *dropped_frames_no_route; diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 7aeba00ac502..e12a786e26b8 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -497,6 +497,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, hopcount, ttl, cpu_to_le32(lifetime), cpu_to_le32(metric), cpu_to_le32(preq_id), sdata); + ifmsh->mshstats.fwded_mcast++; ifmsh->mshstats.fwded_frames++; } } @@ -555,6 +556,8 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, cpu_to_le32(lifetime), cpu_to_le32(metric), 0, sdata); rcu_read_unlock(); + + sdata->u.mesh.mshstats.fwded_unicast++; sdata->u.mesh.mshstats.fwded_frames++; return; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 4cd9e45b1443..7065fd7e7ba2 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1550,7 +1550,10 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; info->control.vif = &rx->sdata->vif; ieee80211_select_queue(local, fwd_skb); - if (!is_multicast_ether_addr(fwd_hdr->addr1)) { + if (is_multicast_ether_addr(fwd_hdr->addr1)) + IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, + fwded_mcast); + else { int err; /* * Save TA to addr1 to send TA a path error if a @@ -1564,6 +1567,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) * later to the pending skb queue. */ if (err) return RX_DROP_MONITOR; + + IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, + fwded_unicast); } IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, fwded_frames); -- cgit v1.2.3 From 11ba964d4f936609a04e8b9f2051f6027ef761ae Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 19 Aug 2009 19:45:50 +0200 Subject: mac80211: fix register_hw error path "cfg80211: fix alignment problem in scan request" introduced a bug into the error path, because now we allocate the entire scan request and not just the channel list (the channel list is allocated together with the scan request) -- on errors we thus also need to free the entire scan request. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/main.c b/net/mac80211/main.c index f80efd7ff5ec..dd3b0816614d 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -930,7 +930,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) fail_workqueue: wiphy_unregister(local->hw.wiphy); fail_wiphy_register: - kfree(local->int_scan_req->channels); + kfree(local->int_scan_req); return result; } EXPORT_SYMBOL(ieee80211_register_hw); -- cgit v1.2.3 From 9e03fdfd05e733e1136d431973625b174029c5e6 Mon Sep 17 00:00:00 2001 From: Javier Cardona Date: Thu, 20 Aug 2009 09:21:45 -0700 Subject: mac80211: Update mesh config IE to 11s draft 3.02 The mesh config information element has changed significantly since draft 1.08 This patch brings it up to date. Thanks to Sam Leffler and Rui Paulo for identifying this. Signed-off-by: Javier Cardona Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 4 ++++ net/mac80211/mesh.c | 49 ++++++++++++++++++++++++++++++++-------------- 2 files changed, 38 insertions(+), 15 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 93e618a980d1..455cc7ade9f5 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -367,6 +367,10 @@ struct ieee80211_if_mesh { u8 mesh_pm_id[4]; /* Congestion Control Mode Identifier */ u8 mesh_cc_id[4]; + /* Synchronization Protocol Identifier */ + u8 mesh_sp_id[4]; + /* Authentication Protocol Identifier */ + u8 mesh_auth_id[4]; /* Local mesh Destination Sequence Number */ u32 dsn; /* Last used PREQ ID */ diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 3185e18c8214..f7364e56f1ee 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -18,8 +18,11 @@ #define PP_OFFSET 1 /* Path Selection Protocol */ #define PM_OFFSET 5 /* Path Selection Metric */ #define CC_OFFSET 9 /* Congestion Control Mode */ -#define CAPAB_OFFSET 17 -#define ACCEPT_PLINKS 0x80 +#define SP_OFFSET 13 /* Synchronization Protocol */ +#define AUTH_OFFSET 17 /* Authentication Protocol */ +#define CAPAB_OFFSET 22 +#define CAPAB_ACCEPT_PLINKS 0x80 +#define CAPAB_FORWARDING 0x10 #define TMR_RUNNING_HK 0 #define TMR_RUNNING_MP 1 @@ -84,7 +87,9 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 && memcmp(ifmsh->mesh_pp_id, ie->mesh_config + PP_OFFSET, 4) == 0 && memcmp(ifmsh->mesh_pm_id, ie->mesh_config + PM_OFFSET, 4) == 0 && - memcmp(ifmsh->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0) + memcmp(ifmsh->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0 && + memcmp(ifmsh->mesh_sp_id, ie->mesh_config + SP_OFFSET, 4) == 0 && + memcmp(ifmsh->mesh_auth_id, ie->mesh_config + AUTH_OFFSET, 4) == 0) return true; return false; @@ -97,7 +102,7 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat */ bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie) { - return (*(ie->mesh_config + CAPAB_OFFSET) & ACCEPT_PLINKS) != 0; + return (*(ie->mesh_config + CAPAB_OFFSET) & CAPAB_ACCEPT_PLINKS) != 0; } /** @@ -123,11 +128,18 @@ void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata) void mesh_ids_set_default(struct ieee80211_if_mesh *sta) { - u8 def_id[4] = {0x00, 0x0F, 0xAC, 0xff}; - - memcpy(sta->mesh_pp_id, def_id, 4); - memcpy(sta->mesh_pm_id, def_id, 4); - memcpy(sta->mesh_cc_id, def_id, 4); + u8 oui[3] = {0x00, 0x0F, 0xAC}; + + memcpy(sta->mesh_pp_id, oui, sizeof(oui)); + memcpy(sta->mesh_pm_id, oui, sizeof(oui)); + memcpy(sta->mesh_cc_id, oui, sizeof(oui)); + memcpy(sta->mesh_sp_id, oui, sizeof(oui)); + memcpy(sta->mesh_auth_id, oui, sizeof(oui)); + sta->mesh_pp_id[sizeof(oui)] = 0; + sta->mesh_pm_id[sizeof(oui)] = 0; + sta->mesh_cc_id[sizeof(oui)] = 0xff; + sta->mesh_sp_id[sizeof(oui)] = 0xff; + sta->mesh_auth_id[sizeof(oui)] = 0x0; } int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) @@ -245,7 +257,7 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) if (sdata->u.mesh.mesh_id_len) memcpy(pos, sdata->u.mesh.mesh_id, sdata->u.mesh.mesh_id_len); - pos = skb_put(skb, 21); + pos = skb_put(skb, 2 + IEEE80211_MESH_CONFIG_LEN); *pos++ = WLAN_EID_MESH_CONFIG; *pos++ = IEEE80211_MESH_CONFIG_LEN; /* Version */ @@ -263,15 +275,22 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) memcpy(pos, sdata->u.mesh.mesh_cc_id, 4); pos += 4; - /* Channel precedence: - * Not running simple channel unification protocol - */ - memset(pos, 0x00, 4); + /* Synchronization protocol identifier */ + memcpy(pos, sdata->u.mesh.mesh_sp_id, 4); pos += 4; + /* Authentication Protocol identifier */ + memcpy(pos, sdata->u.mesh.mesh_auth_id, 4); + pos += 4; + + /* Mesh Formation Info */ + memset(pos, 0x00, 1); + pos += 1; + /* Mesh capability */ sdata->u.mesh.accepting_plinks = mesh_plink_availables(sdata); - *pos++ = sdata->u.mesh.accepting_plinks ? ACCEPT_PLINKS : 0x00; + *pos = CAPAB_FORWARDING; + *pos++ |= sdata->u.mesh.accepting_plinks ? CAPAB_ACCEPT_PLINKS : 0x00; *pos++ = 0x00; return; -- cgit v1.2.3 From 84f6a01ce05fa671f7745b6e041e698a2d1f1341 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 20 Aug 2009 20:02:20 +0200 Subject: mac80211: fix configure_filter invocation after stop Since configure_filter can sleep now, any multicast configuration needed to be postponed to a work struct. This, however, lead to a problem that we could queue the work, stop the device and then afterwards invoke configure_filter which may lead to driver hangs and is a bug. To fix this, we can just cancel the filter work since it's unnecessary to do after stopping the hw. Since there are various places that call drv_stop, and two of them do very similar things, the code for them can be put into a shared function at the same time. Signed-off-by: Johannes Berg Reported-by: Lennert Buytenhek Tested-by: Lennert Buytenhek Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 1 + net/mac80211/iface.c | 6 +----- net/mac80211/pm.c | 13 ++----------- net/mac80211/util.c | 10 ++++++++++ 4 files changed, 14 insertions(+), 16 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 455cc7ade9f5..fa930e01295f 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1086,6 +1086,7 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, /* Suspend/resume and hw reconfiguration */ int ieee80211_reconfig(struct ieee80211_local *local); +void ieee80211_stop_device(struct ieee80211_local *local); #ifdef CONFIG_PM int __ieee80211_suspend(struct ieee80211_hw *hw); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index b161301056df..5940e69fa33c 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -552,11 +552,7 @@ static int ieee80211_stop(struct net_device *dev) ieee80211_recalc_ps(local, -1); if (local->open_count == 0) { - drv_stop(local); - - ieee80211_led_radio(local, false); - - flush_workqueue(local->workqueue); + ieee80211_stop_device(local); tasklet_disable(&local->tx_pending_tasklet); tasklet_disable(&local->tasklet); diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index a5d2f1fb4417..e535f1c988fe 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -107,17 +107,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) } /* stop hardware - this must stop RX */ - if (local->open_count) { - ieee80211_led_radio(local, false); - drv_stop(local); - } - - /* - * flush again, in case driver queued work -- it - * shouldn't be doing (or cancel everything in the - * stop callback) that but better safe than sorry. - */ - flush_workqueue(local->workqueue); + if (local->open_count) + ieee80211_stop_device(local); local->suspended = true; /* need suspended to be visible before quiescing is false */ diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 5eb306377c63..dd6564321369 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1007,6 +1007,16 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local, return supp_rates; } +void ieee80211_stop_device(struct ieee80211_local *local) +{ + ieee80211_led_radio(local, false); + + cancel_work_sync(&local->reconfig_filter); + drv_stop(local); + + flush_workqueue(local->workqueue); +} + int ieee80211_reconfig(struct ieee80211_local *local) { struct ieee80211_hw *hw = &local->hw; -- cgit v1.2.3 From 103bf9f7d35849bce52ad412e4da5063b0716969 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 20 Aug 2009 16:34:15 -0400 Subject: mac80211: remove ieee80211_rx namespace hack With the libipw naming scheme change, it is no longer necessary for mac80211 to avoid the ieee80211_rx name clash. Reported-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/rx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 7065fd7e7ba2..dff2239db6e2 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2440,7 +2440,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, * This is the receive path handler. It is called by a low level driver when an * 802.11 MPDU is received from the hardware. */ -void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) +void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_rate *rate = NULL; @@ -2523,7 +2523,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) rcu_read_unlock(); } -EXPORT_SYMBOL(__ieee80211_rx); +EXPORT_SYMBOL(ieee80211_rx); /* This is a version of the rx handler that can be called from hard irq * context. Post the skb on the queue and schedule the tasklet */ -- cgit v1.2.3 From ea77f12f2cc0f31168f2e0259e65a22202ac4dc2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 21 Aug 2009 14:44:45 +0200 Subject: mac80211: remove tasklet enable/disable Due to the way the tasklets work in mac80211 there's no need to ever disable them. However, we need to clear the pending packets when taking down the last interface because otherwise the tx_pending_tasklet might be queued if the driver mucks with the queues (which it shouldn't). I've had a situation occasionally with ar9170 in which ksoftirq was using 100% CPU time because a disabled tasklet was scheduled, and I think that was due to ar9170 receiving a packet while the tasklet was disabled. That's strange and it really should not do that for other reasons, but there's no need to waste that much CPU time over it, it should just warn instead. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/driver-ops.h | 14 +++++++++++++- net/mac80211/ieee80211_i.h | 3 +++ net/mac80211/iface.c | 9 +-------- net/mac80211/main.c | 2 -- net/mac80211/rx.c | 9 +++++++++ 5 files changed, 26 insertions(+), 11 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index d231c9323ad1..020a94a31106 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -12,7 +12,11 @@ static inline int drv_tx(struct ieee80211_local *local, struct sk_buff *skb) static inline int drv_start(struct ieee80211_local *local) { - int ret = local->ops->start(&local->hw); + int ret; + + local->started = true; + smp_mb(); + ret = local->ops->start(&local->hw); trace_drv_start(local, ret); return ret; } @@ -21,6 +25,14 @@ static inline void drv_stop(struct ieee80211_local *local) { local->ops->stop(&local->hw); trace_drv_stop(local); + + /* sync away all work on the tasklet before clearing started */ + tasklet_disable(&local->tasklet); + tasklet_enable(&local->tasklet); + + barrier(); + + local->started = false; } static inline int drv_add_interface(struct ieee80211_local *local, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index fa930e01295f..dbd8411cc1bd 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -667,6 +667,9 @@ struct ieee80211_local { */ bool quiescing; + /* device is started */ + bool started; + int tx_headroom; /* required headroom for hardware/radiotap */ /* Tasklet and skb queue to process calls from IRQ mode. All frames diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 5940e69fa33c..d134bd79972f 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -277,11 +277,6 @@ static int ieee80211_open(struct net_device *dev) } } - if (local->open_count == 0) { - tasklet_enable(&local->tx_pending_tasklet); - tasklet_enable(&local->tasklet); - } - /* * set_multicast_list will be invoked by the networking core * which will check whether any increments here were done in @@ -552,11 +547,9 @@ static int ieee80211_stop(struct net_device *dev) ieee80211_recalc_ps(local, -1); if (local->open_count == 0) { + ieee80211_clear_tx_pending(local); ieee80211_stop_device(local); - tasklet_disable(&local->tx_pending_tasklet); - tasklet_disable(&local->tasklet); - /* no reconfiguring after stop! */ hw_reconf_flags = 0; } diff --git a/net/mac80211/main.c b/net/mac80211/main.c index dd3b0816614d..797f53942e5f 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -715,12 +715,10 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, skb_queue_head_init(&local->pending[i]); tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, (unsigned long)local); - tasklet_disable(&local->tx_pending_tasklet); tasklet_init(&local->tasklet, ieee80211_tasklet_handler, (unsigned long) local); - tasklet_disable(&local->tasklet); skb_queue_head_init(&local->skb_queue); skb_queue_head_init(&local->skb_queue_unreliable); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index dff2239db6e2..b98f1afbfebf 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2471,6 +2471,15 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) return; } + /* + * The same happens when we're not even started, + * but that's worth a warning. + */ + if (WARN_ON(!local->started)) { + kfree_skb(skb); + return; + } + if (status->flag & RX_FLAG_HT) { /* rate_idx is MCS index */ if (WARN_ON(status->rate_idx < 0 || -- cgit v1.2.3 From 1c4e9ab3f1cc458306b3b910000371ba4f71c4d2 Mon Sep 17 00:00:00 2001 From: Arnd Hannemann Date: Fri, 21 Aug 2009 16:11:30 +0200 Subject: mac80211: Remove unnused throughput field from minstrel_rate. I noticed that the throughput field of the minstrel_rate struct is never used, so remove it. Signed-off-by: Arnd Hannemann Signed-off-by: John W. Linville --- net/mac80211/rc80211_minstrel.h | 1 - 1 file changed, 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h index 869fe0ef951d..38bf4168fc3a 100644 --- a/net/mac80211/rc80211_minstrel.h +++ b/net/mac80211/rc80211_minstrel.h @@ -33,7 +33,6 @@ struct minstrel_rate { /* per-rate throughput */ u32 cur_tp; - u32 throughput; u64 succ_hist; u64 att_hist; -- cgit v1.2.3 From 77a980dc6c4674fc7741d72b9775135669318d8d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 24 Aug 2009 11:46:30 +0200 Subject: mac80211: fix RX skb leaks In mac80211's RX path some of the warnings that warn about drivers passing invalid status values leak the skb, fix that by refactoring the code. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/rx.c | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b98f1afbfebf..c01588f9d453 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2447,17 +2447,13 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) struct ieee80211_supported_band *sband; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); - if (status->band < 0 || - status->band >= IEEE80211_NUM_BANDS) { - WARN_ON(1); - return; - } + if (WARN_ON(status->band < 0 || + status->band >= IEEE80211_NUM_BANDS)) + goto drop; sband = local->hw.wiphy->bands[status->band]; - if (!sband) { - WARN_ON(1); - return; - } + if (WARN_ON(!sband)) + goto drop; /* * If we're suspending, it is possible although not too likely @@ -2466,25 +2462,21 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) * that might, for example, cause stations to be added or other * driver callbacks be invoked. */ - if (unlikely(local->quiescing || local->suspended)) { - kfree_skb(skb); - return; - } + if (unlikely(local->quiescing || local->suspended)) + goto drop; /* * The same happens when we're not even started, * but that's worth a warning. */ - if (WARN_ON(!local->started)) { - kfree_skb(skb); - return; - } + if (WARN_ON(!local->started)) + goto drop; if (status->flag & RX_FLAG_HT) { /* rate_idx is MCS index */ if (WARN_ON(status->rate_idx < 0 || status->rate_idx >= 76)) - return; + goto drop; /* HT rates are not in the table - use the highest legacy rate * for now since other parts of mac80211 may not yet be fully * MCS aware. */ @@ -2492,7 +2484,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) } else { if (WARN_ON(status->rate_idx < 0 || status->rate_idx >= sband->n_bitrates)) - return; + goto drop; rate = &sband->bitrates[status->rate_idx]; } @@ -2531,6 +2523,10 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) __ieee80211_rx_handle_packet(hw, skb, rate); rcu_read_unlock(); + + return; + drop: + kfree_skb(skb); } EXPORT_SYMBOL(ieee80211_rx); -- cgit v1.2.3 From eadac6bf95e1945bb64e6f8f22d8509391645e2e Mon Sep 17 00:00:00 2001 From: Arnd Hannemann Date: Mon, 24 Aug 2009 20:51:46 +0200 Subject: mac80211: Fix output of minstrels rc_stats An integer overflow in the minstrel debug code prevented the throughput to be displayed correctly. This patch fixes that, by permutating operations like proposed by Pavel Roskin. Signed-off-by: Arnd Hannemann Signed-off-by: John W. Linville --- net/mac80211/rc80211_minstrel_debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/rc80211_minstrel_debugfs.c b/net/mac80211/rc80211_minstrel_debugfs.c index 98f480708050..3d72ec5730d4 100644 --- a/net/mac80211/rc80211_minstrel_debugfs.c +++ b/net/mac80211/rc80211_minstrel_debugfs.c @@ -83,7 +83,7 @@ minstrel_stats_open(struct inode *inode, struct file *file) p += sprintf(p, "%3u%s", mr->bitrate / 2, (mr->bitrate & 1 ? ".5" : " ")); - tp = ((mr->cur_tp * 96) / 18000) >> 10; + tp = mr->cur_tp / ((18000 << 10) / 96); prob = mr->cur_prob / 18; eprob = mr->probability / 18; -- cgit v1.2.3 From 15db0b7fd872b0312033666d3a82e1214a227ec0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 25 Aug 2009 16:33:47 +0200 Subject: mac80211: fix scan cancel on ifdown When an interface is taken down while a scan is pending -- i.e. a scan request was accepted but not yet acted upon due to other work being in progress -- we currently do not properly cancel that scan and end up getting stuck. Fix this by doing better checks when an interface is taken down. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/iface.c | 26 ++------------------------ net/mac80211/scan.c | 9 ++++++--- 2 files changed, 8 insertions(+), 27 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index d134bd79972f..f6005adcbf90 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -497,30 +497,8 @@ static int ieee80211_stop(struct net_device *dev) } /* fall through */ default: - if (local->scan_sdata == sdata) { - if (!local->ops->hw_scan) - cancel_delayed_work_sync(&local->scan_work); - /* - * The software scan can no longer run now, so we can - * clear out the scan_sdata reference. However, the - * hardware scan may still be running. The complete - * function must be prepared to handle a NULL value. - */ - local->scan_sdata = NULL; - /* - * The memory barrier guarantees that another CPU - * that is hardware-scanning will now see the fact - * that this interface is gone. - */ - smp_mb(); - /* - * If software scanning, complete the scan but since - * the scan_sdata is NULL already don't send out a - * scan event to userspace -- the scan is incomplete. - */ - if (test_bit(SCAN_SW_SCANNING, &local->scanning)) - ieee80211_scan_completed(&local->hw, true); - } + if (local->scan_sdata == sdata) + ieee80211_scan_cancel(local); /* * Disable beaconing for AP and mesh, IBSS can't diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 1e04be6b9129..039901109fa1 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -280,6 +280,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) if (local->scan_req != local->int_scan_req) cfg80211_scan_done(local->scan_req, aborted); local->scan_req = NULL; + local->scan_sdata = NULL; was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning); local->scanning = 0; @@ -660,6 +661,7 @@ void ieee80211_scan_work(struct work_struct *work) int rc; local->scan_req = NULL; + local->scan_sdata = NULL; rc = __ieee80211_start_scan(sdata, req); mutex_unlock(&local->scan_mtx); @@ -742,7 +744,7 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, void ieee80211_scan_cancel(struct ieee80211_local *local) { - bool swscan; + bool abortscan; cancel_delayed_work_sync(&local->scan_work); @@ -751,9 +753,10 @@ void ieee80211_scan_cancel(struct ieee80211_local *local) * queued -- mostly at suspend under RTNL. */ mutex_lock(&local->scan_mtx); - swscan = test_bit(SCAN_SW_SCANNING, &local->scanning); + abortscan = test_bit(SCAN_SW_SCANNING, &local->scanning) || + (!local->scanning && local->scan_req); mutex_unlock(&local->scan_mtx); - if (swscan) + if (abortscan) ieee80211_scan_completed(&local->hw, true); } -- cgit v1.2.3 From 5bf6fcc2bbfb90d997f88c969f1ceee35d064a24 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 25 Aug 2009 17:44:28 +0300 Subject: mac80211: Check pending scan request after having processed mgd work When the queued management work items are processed in ieee80211_sta_work() an item could be removed. This could change the anybusy from true to false, so we better check whether we can start a new scan only after having processed the pending work first. Signed-off-by: Jouni Malinen Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c374d2d73fa4..97a278a2f48e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2123,25 +2123,9 @@ static void ieee80211_sta_work(struct work_struct *work) } } - list_for_each_entry(wk, &ifmgd->work_list, list) { - if (wk->state != IEEE80211_MGD_STATE_IDLE) { - anybusy = true; - break; - } - } ieee80211_recalc_idle(local); - if (!anybusy) { - mutex_unlock(&ifmgd->mtx); - - if (test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) - ieee80211_queue_delayed_work(&local->hw, - &local->scan_work, - round_jiffies_relative(0)); - return; - } - list_for_each_entry_safe(wk, tmp, &ifmgd->work_list, list) { if (time_is_after_jiffies(wk->timeout)) { /* @@ -2187,6 +2171,18 @@ static void ieee80211_sta_work(struct work_struct *work) } } + list_for_each_entry(wk, &ifmgd->work_list, list) { + if (wk->state != IEEE80211_MGD_STATE_IDLE) { + anybusy = true; + break; + } + } + if (!anybusy && + test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) + ieee80211_queue_delayed_work(&local->hw, + &local->scan_work, + round_jiffies_relative(0)); + mutex_unlock(&ifmgd->mtx); list_for_each_entry_safe(wk, tmp, &free_work, list) { -- cgit v1.2.3 From d0cf9c0dadcdc89a755bcb301cfc9c796eb28ccf Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 31 Aug 2009 19:50:57 +0000 Subject: wireless: convert drivers to netdev_tx_t Mostly just simple conversions: * ray_cs had bogus return of NET_TX_LOCKED but driver was not using NETIF_F_LLTX * hostap and ipw2x00 had some code that returned value from a called function that also had to change to return netdev_tx_t Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/mac80211/ieee80211_i.h | 6 ++++-- net/mac80211/tx.c | 8 ++++---- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index dbd8411cc1bd..588005c84a6d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1050,8 +1050,10 @@ void ieee80211_recalc_idle(struct ieee80211_local *local); /* tx handling */ void ieee80211_clear_tx_pending(struct ieee80211_local *local); void ieee80211_tx_pending(unsigned long data); -int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev); -int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); +netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, + struct net_device *dev); +netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, + struct net_device *dev); /* HT */ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 0c08d1e60cb5..5143d203256b 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1483,8 +1483,8 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, dev_put(sdata->dev); } -int ieee80211_monitor_start_xmit(struct sk_buff *skb, - struct net_device *dev) +netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_channel *chan = local->hw.conf.channel; @@ -1568,8 +1568,8 @@ fail: * encapsulated packet will then be passed to master interface, wlan#.11, for * transmission (through low-level driver). */ -int ieee80211_subif_start_xmit(struct sk_buff *skb, - struct net_device *dev) +netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, + struct net_device *dev) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = sdata->local; -- cgit v1.2.3 From 5ca1b998d33c39819fca2b675d80c4469e705f2d Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 1 Sep 2009 19:25:05 +0000 Subject: net: file_operations should be const All instances of file_operations should be const. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/mac80211/rc80211_minstrel_debugfs.c | 2 +- net/mac80211/rc80211_pid_debugfs.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/rc80211_minstrel_debugfs.c b/net/mac80211/rc80211_minstrel_debugfs.c index 3d72ec5730d4..a715d9454f64 100644 --- a/net/mac80211/rc80211_minstrel_debugfs.c +++ b/net/mac80211/rc80211_minstrel_debugfs.c @@ -139,7 +139,7 @@ minstrel_stats_release(struct inode *inode, struct file *file) return 0; } -static struct file_operations minstrel_stat_fops = { +static const struct file_operations minstrel_stat_fops = { .owner = THIS_MODULE, .open = minstrel_stats_open, .read = minstrel_stats_read, diff --git a/net/mac80211/rc80211_pid_debugfs.c b/net/mac80211/rc80211_pid_debugfs.c index a08a9b530347..a59043fbb0ff 100644 --- a/net/mac80211/rc80211_pid_debugfs.c +++ b/net/mac80211/rc80211_pid_debugfs.c @@ -198,7 +198,7 @@ static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf, #undef RC_PID_PRINT_BUF_SIZE -static struct file_operations rc_pid_fop_events = { +static const struct file_operations rc_pid_fop_events = { .owner = THIS_MODULE, .read = rate_control_pid_events_read, .poll = rate_control_pid_events_poll, -- cgit v1.2.3 From abd8ea22c23c917f56fefcda8a4468fbc2247d7f Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 1 Sep 2009 08:22:46 -0700 Subject: wireless: remove mac80211 rate selection extra menu We can just display this upon enabling mac80211 with an 'if MAC80211 != n' check. Cc: Johannes Berg Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- net/mac80211/Kconfig | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 9db4ff836a3d..4d5543af3123 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -13,8 +13,7 @@ config MAC80211 comment "CFG80211 needs to be enabled for MAC80211" depends on CFG80211=n -menu "Rate control algorithm selection" - depends on MAC80211 != n +if MAC80211 != n config MAC80211_RC_PID bool "PID controller based rate control algorithm" if EMBEDDED @@ -61,7 +60,7 @@ config MAC80211_RC_DEFAULT default "pid" if MAC80211_RC_DEFAULT_PID default "" -endmenu +endif config MAC80211_MESH bool "Enable mac80211 mesh networking (pre-802.11s) support" -- cgit v1.2.3 From 384912ed194e43c03ad1cdaa09b0b1e488c34d46 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 31 Aug 2009 21:08:19 +0000 Subject: net: Add DEVTYPE support for Ethernet based devices The Ethernet framing is used for a lot of devices these days. Most prominent are WiFi and WiMAX based devices. However for userspace application it is important to classify these devices correctly and not only see them as Ethernet devices. The daemons like HAL, DeviceKit or even NetworkManager with udev support tries to do the classification in userspace with a lot trickery and extra system calls. This is not good and actually reaches its limitations. Especially since the kernel does know the type of the Ethernet device it is pretty stupid. To solve this problem the underlying device type needs to be set and then the value will be exported as DEVTYPE via uevents and available within udev. # cat /sys/class/net/wlan0/uevent DEVTYPE=wlan INTERFACE=wlan0 IFINDEX=5 This is similar to subsystems like USB and SCSI that distinguish between hosts, devices, disks, partitions etc. The new SET_NETDEV_DEVTYPE() is a convenience helper to set the actual device type. All device types are free form, but for convenience the same strings as used with RFKILL are choosen. Signed-off-by: Marcel Holtmann Signed-off-by: David S. Miller --- net/mac80211/iface.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'net/mac80211') diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index f6005adcbf90..b8295cbd7e8f 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -754,6 +754,10 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, return 0; } +static struct device_type wiphy_type = { + .name = "wlan", +}; + int ieee80211_if_add(struct ieee80211_local *local, const char *name, struct net_device **new_dev, enum nl80211_iftype type, struct vif_params *params) @@ -785,6 +789,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); + SET_NETDEV_DEVTYPE(ndev, &wiphy_type); /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ sdata = netdev_priv(ndev); -- cgit v1.2.3