aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-01-20 07:55:21 -0500
committerJohn W. Linville <linville@tuxdriver.com>2012-02-06 14:48:24 -0500
commitf09603a259ffef69ad4516a04eb06cd65ac522fe (patch)
tree3f826769c697eb15a76771e25291bbb54f9f58ab /net
parent71ec375c75095002f36f083ceb32bbb8725734ae (diff)
mac80211: add sta_state callback
(based on Eliad's patch) Add a callback to notify the low-level driver whenever the state of a station changes. The driver is only notified when the station is actually in the mac80211 hash table, not for pre-insert state transitions. To allow the driver to replace sta_add/remove calls with this, call extra transitions with the NOTEXIST state. This callback can fail, so we need to be careful in handling it when a station is inserted, particularly in the IBSS case where we still keep the station entry around for mac80211 purposes. Signed-off-by: Eliad Peller <eliad@wizery.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/driver-ops.h22
-rw-r--r--net/mac80211/driver-trace.h32
-rw-r--r--net/mac80211/main.c3
-rw-r--r--net/mac80211/pm.c10
-rw-r--r--net/mac80211/sta_info.c106
-rw-r--r--net/mac80211/sta_info.h9
-rw-r--r--net/mac80211/util.c10
7 files changed, 164 insertions, 28 deletions
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index b8673f6100df..4bd266ec5333 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -478,6 +478,28 @@ static inline void drv_sta_remove(struct ieee80211_local *local,
478 trace_drv_return_void(local); 478 trace_drv_return_void(local);
479} 479}
480 480
481static inline __must_check
482int drv_sta_state(struct ieee80211_local *local,
483 struct ieee80211_sub_if_data *sdata,
484 struct sta_info *sta,
485 enum ieee80211_sta_state old_state,
486 enum ieee80211_sta_state new_state)
487{
488 int ret = 0;
489
490 might_sleep();
491
492 sdata = get_bss_sdata(sdata);
493 check_sdata_in_driver(sdata);
494
495 trace_drv_sta_state(local, sdata, &sta->sta, old_state, new_state);
496 if (local->ops->sta_state)
497 ret = local->ops->sta_state(&local->hw, &sdata->vif, &sta->sta,
498 old_state, new_state);
499 trace_drv_return_int(local, ret);
500 return ret;
501}
502
481static inline int drv_conf_tx(struct ieee80211_local *local, 503static inline int drv_conf_tx(struct ieee80211_local *local,
482 struct ieee80211_sub_if_data *sdata, u16 queue, 504 struct ieee80211_sub_if_data *sdata, u16 queue,
483 const struct ieee80211_tx_queue_params *params) 505 const struct ieee80211_tx_queue_params *params)
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index 6e9df8fd8fb8..384e2f08c187 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -635,6 +635,38 @@ TRACE_EVENT(drv_sta_notify,
635 ) 635 )
636); 636);
637 637
638TRACE_EVENT(drv_sta_state,
639 TP_PROTO(struct ieee80211_local *local,
640 struct ieee80211_sub_if_data *sdata,
641 struct ieee80211_sta *sta,
642 enum ieee80211_sta_state old_state,
643 enum ieee80211_sta_state new_state),
644
645 TP_ARGS(local, sdata, sta, old_state, new_state),
646
647 TP_STRUCT__entry(
648 LOCAL_ENTRY
649 VIF_ENTRY
650 STA_ENTRY
651 __field(u32, old_state)
652 __field(u32, new_state)
653 ),
654
655 TP_fast_assign(
656 LOCAL_ASSIGN;
657 VIF_ASSIGN;
658 STA_ASSIGN;
659 __entry->old_state = old_state;
660 __entry->new_state = new_state;
661 ),
662
663 TP_printk(
664 LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " state: %d->%d",
665 LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG,
666 __entry->old_state, __entry->new_state
667 )
668);
669
638TRACE_EVENT(drv_sta_add, 670TRACE_EVENT(drv_sta_add,
639 TP_PROTO(struct ieee80211_local *local, 671 TP_PROTO(struct ieee80211_local *local,
640 struct ieee80211_sub_if_data *sdata, 672 struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 6192caadfab9..f4fc540aac17 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -535,6 +535,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
535 int priv_size, i; 535 int priv_size, i;
536 struct wiphy *wiphy; 536 struct wiphy *wiphy;
537 537
538 if (WARN_ON(ops->sta_state && (ops->sta_add || ops->sta_remove)))
539 return NULL;
540
538 /* Ensure 32-byte alignment of our private data and hw private data. 541 /* Ensure 32-byte alignment of our private data and hw private data.
539 * We use the wiphy priv data for both our ieee80211_local and for 542 * We use the wiphy priv data for both our ieee80211_local and for
540 * the driver's private data 543 * the driver's private data
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index c65ff471acce..af49ac4f0826 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -97,9 +97,17 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
97 /* tear down aggregation sessions and remove STAs */ 97 /* tear down aggregation sessions and remove STAs */
98 mutex_lock(&local->sta_mtx); 98 mutex_lock(&local->sta_mtx);
99 list_for_each_entry(sta, &local->sta_list, list) { 99 list_for_each_entry(sta, &local->sta_list, list) {
100 if (sta->uploaded) 100 if (sta->uploaded) {
101 enum ieee80211_sta_state state;
102
101 drv_sta_remove(local, sta->sdata, &sta->sta); 103 drv_sta_remove(local, sta->sdata, &sta->sta);
102 104
105 state = sta->sta_state;
106 for (; state > IEEE80211_STA_NOTEXIST; state--)
107 WARN_ON(drv_sta_state(local, sdata, sta,
108 state, state - 1));
109 }
110
103 mesh_plink_quiesce(sta); 111 mesh_plink_quiesce(sta);
104 } 112 }
105 mutex_unlock(&local->sta_mtx); 113 mutex_unlock(&local->sta_mtx);
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 464bc691644b..fcd9027c6699 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -351,6 +351,38 @@ static int sta_info_insert_check(struct sta_info *sta)
351 return 0; 351 return 0;
352} 352}
353 353
354static int sta_info_insert_drv_state(struct ieee80211_local *local,
355 struct ieee80211_sub_if_data *sdata,
356 struct sta_info *sta)
357{
358 enum ieee80211_sta_state state;
359 int err = 0;
360
361 for (state = IEEE80211_STA_NOTEXIST; state < sta->sta_state; state++) {
362 err = drv_sta_state(local, sdata, sta, state, state + 1);
363 if (err)
364 break;
365 }
366
367 if (!err) {
368 sta->uploaded = true;
369 return 0;
370 }
371
372 if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
373 printk(KERN_DEBUG
374 "%s: failed to move IBSS STA %pM to state %d (%d) - keeping it anyway.\n",
375 sdata->name, sta->sta.addr, state + 1, err);
376 err = 0;
377 }
378
379 /* unwind on error */
380 for (; state > IEEE80211_STA_NOTEXIST; state--)
381 WARN_ON(drv_sta_state(local, sdata, sta, state, state - 1));
382
383 return err;
384}
385
354/* 386/*
355 * should be called with sta_mtx locked 387 * should be called with sta_mtx locked
356 * this function replaces the mutex lock 388 * this function replaces the mutex lock
@@ -392,8 +424,11 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
392 printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to " 424 printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to "
393 "driver (%d) - keeping it anyway.\n", 425 "driver (%d) - keeping it anyway.\n",
394 sdata->name, sta->sta.addr, err); 426 sdata->name, sta->sta.addr, err);
395 } else 427 } else {
396 sta->uploaded = true; 428 err = sta_info_insert_drv_state(local, sdata, sta);
429 if (err)
430 goto out_err;
431 }
397 } 432 }
398 433
399 if (!dummy_reinsert) { 434 if (!dummy_reinsert) {
@@ -759,15 +794,19 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
759 RCU_INIT_POINTER(sdata->u.vlan.sta, NULL); 794 RCU_INIT_POINTER(sdata->u.vlan.sta, NULL);
760 795
761 while (sta->sta_state > IEEE80211_STA_NONE) { 796 while (sta->sta_state > IEEE80211_STA_NONE) {
762 int err = sta_info_move_state(sta, sta->sta_state - 1); 797 ret = sta_info_move_state(sta, sta->sta_state - 1);
763 if (err) { 798 if (ret) {
764 WARN_ON_ONCE(1); 799 WARN_ON_ONCE(1);
765 break; 800 break;
766 } 801 }
767 } 802 }
768 803
769 if (sta->uploaded) 804 if (sta->uploaded) {
770 drv_sta_remove(local, sdata, &sta->sta); 805 drv_sta_remove(local, sdata, &sta->sta);
806 ret = drv_sta_state(local, sdata, sta, IEEE80211_STA_NONE,
807 IEEE80211_STA_NOTEXIST);
808 WARN_ON_ONCE(ret != 0);
809 }
771 810
772 /* 811 /*
773 * At this point, after we wait for an RCU grace period, 812 * At this point, after we wait for an RCU grace period,
@@ -1404,20 +1443,58 @@ int sta_info_move_state(struct sta_info *sta,
1404 if (sta->sta_state == new_state) 1443 if (sta->sta_state == new_state)
1405 return 0; 1444 return 0;
1406 1445
1446 /* check allowed transitions first */
1447
1448 switch (new_state) {
1449 case IEEE80211_STA_NONE:
1450 if (sta->sta_state != IEEE80211_STA_AUTH)
1451 return -EINVAL;
1452 break;
1453 case IEEE80211_STA_AUTH:
1454 if (sta->sta_state != IEEE80211_STA_NONE &&
1455 sta->sta_state != IEEE80211_STA_ASSOC)
1456 return -EINVAL;
1457 break;
1458 case IEEE80211_STA_ASSOC:
1459 if (sta->sta_state != IEEE80211_STA_AUTH &&
1460 sta->sta_state != IEEE80211_STA_AUTHORIZED)
1461 return -EINVAL;
1462 break;
1463 case IEEE80211_STA_AUTHORIZED:
1464 if (sta->sta_state != IEEE80211_STA_ASSOC)
1465 return -EINVAL;
1466 break;
1467 default:
1468 WARN(1, "invalid state %d", new_state);
1469 return -EINVAL;
1470 }
1471
1472 printk(KERN_DEBUG "%s: moving STA %pM to state %d\n",
1473 sta->sdata->name, sta->sta.addr, new_state);
1474
1475 /*
1476 * notify the driver before the actual changes so it can
1477 * fail the transition
1478 */
1479 if (test_sta_flag(sta, WLAN_STA_INSERTED)) {
1480 int err = drv_sta_state(sta->local, sta->sdata, sta,
1481 sta->sta_state, new_state);
1482 if (err)
1483 return err;
1484 }
1485
1486 /* reflect the change in all state variables */
1487
1407 switch (new_state) { 1488 switch (new_state) {
1408 case IEEE80211_STA_NONE: 1489 case IEEE80211_STA_NONE:
1409 if (sta->sta_state == IEEE80211_STA_AUTH) 1490 if (sta->sta_state == IEEE80211_STA_AUTH)
1410 clear_bit(WLAN_STA_AUTH, &sta->_flags); 1491 clear_bit(WLAN_STA_AUTH, &sta->_flags);
1411 else
1412 return -EINVAL;
1413 break; 1492 break;
1414 case IEEE80211_STA_AUTH: 1493 case IEEE80211_STA_AUTH:
1415 if (sta->sta_state == IEEE80211_STA_NONE) 1494 if (sta->sta_state == IEEE80211_STA_NONE)
1416 set_bit(WLAN_STA_AUTH, &sta->_flags); 1495 set_bit(WLAN_STA_AUTH, &sta->_flags);
1417 else if (sta->sta_state == IEEE80211_STA_ASSOC) 1496 else if (sta->sta_state == IEEE80211_STA_ASSOC)
1418 clear_bit(WLAN_STA_ASSOC, &sta->_flags); 1497 clear_bit(WLAN_STA_ASSOC, &sta->_flags);
1419 else
1420 return -EINVAL;
1421 break; 1498 break;
1422 case IEEE80211_STA_ASSOC: 1499 case IEEE80211_STA_ASSOC:
1423 if (sta->sta_state == IEEE80211_STA_AUTH) { 1500 if (sta->sta_state == IEEE80211_STA_AUTH) {
@@ -1426,24 +1503,19 @@ int sta_info_move_state(struct sta_info *sta,
1426 if (sta->sdata->vif.type == NL80211_IFTYPE_AP) 1503 if (sta->sdata->vif.type == NL80211_IFTYPE_AP)
1427 atomic_dec(&sta->sdata->u.ap.num_sta_authorized); 1504 atomic_dec(&sta->sdata->u.ap.num_sta_authorized);
1428 clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags); 1505 clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
1429 } else 1506 }
1430 return -EINVAL;
1431 break; 1507 break;
1432 case IEEE80211_STA_AUTHORIZED: 1508 case IEEE80211_STA_AUTHORIZED:
1433 if (sta->sta_state == IEEE80211_STA_ASSOC) { 1509 if (sta->sta_state == IEEE80211_STA_ASSOC) {
1434 if (sta->sdata->vif.type == NL80211_IFTYPE_AP) 1510 if (sta->sdata->vif.type == NL80211_IFTYPE_AP)
1435 atomic_inc(&sta->sdata->u.ap.num_sta_authorized); 1511 atomic_inc(&sta->sdata->u.ap.num_sta_authorized);
1436 set_bit(WLAN_STA_AUTHORIZED, &sta->_flags); 1512 set_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
1437 } else 1513 }
1438 return -EINVAL;
1439 break; 1514 break;
1440 default: 1515 default:
1441 WARN(1, "invalid state %d", new_state); 1516 break;
1442 return -EINVAL;
1443 } 1517 }
1444 1518
1445 printk(KERN_DEBUG "%s: moving STA %pM to state %d\n",
1446 sta->sdata->name, sta->sta.addr, new_state);
1447 sta->sta_state = new_state; 1519 sta->sta_state = new_state;
1448 1520
1449 return 0; 1521 return 0;
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index da4b03c1c3bc..2ee808860007 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -75,15 +75,6 @@ enum ieee80211_sta_info_flags {
75 WLAN_STA_INSERTED, 75 WLAN_STA_INSERTED,
76}; 76};
77 77
78enum ieee80211_sta_state {
79 /* NOTE: These need to be ordered correctly! */
80 IEEE80211_STA_NOTEXIST,
81 IEEE80211_STA_NONE,
82 IEEE80211_STA_AUTH,
83 IEEE80211_STA_ASSOC,
84 IEEE80211_STA_AUTHORIZED,
85};
86
87#define STA_TID_NUM 16 78#define STA_TID_NUM 16
88#define ADDBA_RESP_INTERVAL HZ 79#define ADDBA_RESP_INTERVAL HZ
89#define HT_AGG_MAX_RETRIES 15 80#define HT_AGG_MAX_RETRIES 15
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index d4966e88aa49..8f8b4ecc776f 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1184,8 +1184,16 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1184 /* add STAs back */ 1184 /* add STAs back */
1185 mutex_lock(&local->sta_mtx); 1185 mutex_lock(&local->sta_mtx);
1186 list_for_each_entry(sta, &local->sta_list, list) { 1186 list_for_each_entry(sta, &local->sta_list, list) {
1187 if (sta->uploaded) 1187 if (sta->uploaded) {
1188 enum ieee80211_sta_state state;
1189
1188 WARN_ON(drv_sta_add(local, sta->sdata, &sta->sta)); 1190 WARN_ON(drv_sta_add(local, sta->sdata, &sta->sta));
1191
1192 for (state = IEEE80211_STA_NOTEXIST;
1193 state < sta->sta_state - 1; state++)
1194 WARN_ON(drv_sta_state(local, sta->sdata, sta,
1195 state, state + 1));
1196 }
1189 } 1197 }
1190 mutex_unlock(&local->sta_mtx); 1198 mutex_unlock(&local->sta_mtx);
1191 1199