diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-03-24 04:35:46 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-03-27 20:13:20 -0400 |
commit | 4bbf4d56583dd52c429d88f43cb614bdbe5deea6 (patch) | |
tree | 7a3f902a08820342254e0d67607fe870b02620b3 /net/wireless/nl80211.c | |
parent | 3832c287f11ba001bbe48e9be8c59cb9f71f6b43 (diff) |
cfg80211: fix locking in nl80211_set_wiphy
Luis reports that there's a circular locking dependency;
this is because cfg80211_dev_rename() will acquire the
cfg80211_mutex while the device mutex is held, while
this normally is done the other way around. The solution
is to open-code the device-getting in nl80211_set_wiphy
and require holding the mutex around cfg80211_dev_rename
rather than acquiring it within.
Also fix a bug -- rtnl locking is expected by drivers so
we need to provide it.
Reported-by: Luis R. Rodriguez <lrodriguez@atheros.com>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 28 |
1 files changed, 20 insertions, 8 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 8808431bd58..353e1a4ece8 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -366,16 +366,26 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
366 | int result = 0, rem_txq_params = 0; | 366 | int result = 0, rem_txq_params = 0; |
367 | struct nlattr *nl_txq_params; | 367 | struct nlattr *nl_txq_params; |
368 | 368 | ||
369 | rdev = cfg80211_get_dev_from_info(info); | 369 | rtnl_lock(); |
370 | if (IS_ERR(rdev)) | 370 | |
371 | return PTR_ERR(rdev); | 371 | mutex_lock(&cfg80211_mutex); |
372 | |||
373 | rdev = __cfg80211_drv_from_info(info); | ||
374 | if (IS_ERR(rdev)) { | ||
375 | result = PTR_ERR(rdev); | ||
376 | goto unlock; | ||
377 | } | ||
372 | 378 | ||
373 | if (info->attrs[NL80211_ATTR_WIPHY_NAME]) { | 379 | mutex_lock(&rdev->mtx); |
380 | |||
381 | if (info->attrs[NL80211_ATTR_WIPHY_NAME]) | ||
374 | result = cfg80211_dev_rename( | 382 | result = cfg80211_dev_rename( |
375 | rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME])); | 383 | rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME])); |
376 | if (result) | 384 | |
377 | goto bad_res; | 385 | mutex_unlock(&cfg80211_mutex); |
378 | } | 386 | |
387 | if (result) | ||
388 | goto bad_res; | ||
379 | 389 | ||
380 | if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) { | 390 | if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) { |
381 | struct ieee80211_txq_params txq_params; | 391 | struct ieee80211_txq_params txq_params; |
@@ -471,7 +481,9 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
471 | 481 | ||
472 | 482 | ||
473 | bad_res: | 483 | bad_res: |
474 | cfg80211_put_dev(rdev); | 484 | mutex_unlock(&rdev->mtx); |
485 | unlock: | ||
486 | rtnl_unlock(); | ||
475 | return result; | 487 | return result; |
476 | } | 488 | } |
477 | 489 | ||