aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorLuis R. Rodriguez <mcgrof@do-not-panic.com>2013-11-05 12:18:06 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-11-25 14:51:12 -0500
commitb23e7a9e6b1f4c3070f9ce59e82b9dff69b11fe1 (patch)
treec06c05cfa067804a7f244f28922ff09ed6cd7ce0 /net
parent21636c7faae0a980e73f366e164ffaa77a424786 (diff)
cfg80211: process country IE regulatory requests on their own
This is the last split up of the old unified __regultory_hint() processing set of functionality, it moves the country IE processing all on its own. This makes it easier to follow and read what exactly is going on for the case of processing country IEs. Signed-off-by: Luis R. Rodriguez <mcgrof@do-not-panic.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net')
-rw-r--r--net/wireless/reg.c201
1 files changed, 68 insertions, 133 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 7188ef9f07b6..aef39243595a 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1322,62 +1322,6 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
1322} 1322}
1323EXPORT_SYMBOL(wiphy_apply_custom_regulatory); 1323EXPORT_SYMBOL(wiphy_apply_custom_regulatory);
1324 1324
1325/* This has the logic which determines when a new request
1326 * should be ignored. */
1327static enum reg_request_treatment
1328get_reg_request_treatment(struct wiphy *wiphy,
1329 struct regulatory_request *pending_request)
1330{
1331 struct wiphy *last_wiphy = NULL;
1332 struct regulatory_request *lr = get_last_request();
1333
1334 /* All initial requests are respected */
1335 if (!lr)
1336 return REG_REQ_OK;
1337
1338 switch (pending_request->initiator) {
1339 case NL80211_REGDOM_SET_BY_CORE:
1340 case NL80211_REGDOM_SET_BY_USER:
1341 case NL80211_REGDOM_SET_BY_DRIVER:
1342 return REG_REQ_IGNORE;
1343 case NL80211_REGDOM_SET_BY_COUNTRY_IE:
1344 if (reg_request_cell_base(lr)) {
1345 /* Trust a Cell base station over the AP's country IE */
1346 if (regdom_changes(pending_request->alpha2))
1347 return REG_REQ_IGNORE;
1348 return REG_REQ_ALREADY_SET;
1349 }
1350
1351 last_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
1352
1353 if (unlikely(!is_an_alpha2(pending_request->alpha2)))
1354 return -EINVAL;
1355 if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
1356 if (last_wiphy != wiphy) {
1357 /*
1358 * Two cards with two APs claiming different
1359 * Country IE alpha2s. We could
1360 * intersect them, but that seems unlikely
1361 * to be correct. Reject second one for now.
1362 */
1363 if (regdom_changes(pending_request->alpha2))
1364 return REG_REQ_IGNORE;
1365 return REG_REQ_ALREADY_SET;
1366 }
1367 /*
1368 * Two consecutive Country IE hints on the same wiphy.
1369 * This should be picked up early by the driver/stack
1370 */
1371 if (WARN_ON(regdom_changes(pending_request->alpha2)))
1372 return REG_REQ_OK;
1373 return REG_REQ_ALREADY_SET;
1374 }
1375 return REG_REQ_OK;
1376 }
1377
1378 return REG_REQ_IGNORE;
1379}
1380
1381static void reg_set_request_processed(void) 1325static void reg_set_request_processed(void)
1382{ 1326{
1383 bool need_more_processing = false; 1327 bool need_more_processing = false;
@@ -1581,96 +1525,92 @@ reg_process_hint_driver(struct wiphy *wiphy,
1581 return REG_REQ_OK; 1525 return REG_REQ_OK;
1582} 1526}
1583 1527
1528static enum reg_request_treatment
1529__reg_process_hint_country_ie(struct wiphy *wiphy,
1530 struct regulatory_request *country_ie_request)
1531{
1532 struct wiphy *last_wiphy = NULL;
1533 struct regulatory_request *lr = get_last_request();
1534
1535 if (reg_request_cell_base(lr)) {
1536 /* Trust a Cell base station over the AP's country IE */
1537 if (regdom_changes(country_ie_request->alpha2))
1538 return REG_REQ_IGNORE;
1539 return REG_REQ_ALREADY_SET;
1540 }
1541
1542 last_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
1543
1544 if (unlikely(!is_an_alpha2(country_ie_request->alpha2)))
1545 return -EINVAL;
1546 if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
1547 if (last_wiphy != wiphy) {
1548 /*
1549 * Two cards with two APs claiming different
1550 * Country IE alpha2s. We could
1551 * intersect them, but that seems unlikely
1552 * to be correct. Reject second one for now.
1553 */
1554 if (regdom_changes(country_ie_request->alpha2))
1555 return REG_REQ_IGNORE;
1556 return REG_REQ_ALREADY_SET;
1557 }
1558 /*
1559 * Two consecutive Country IE hints on the same wiphy.
1560 * This should be picked up early by the driver/stack
1561 */
1562 if (WARN_ON(regdom_changes(country_ie_request->alpha2)))
1563 return REG_REQ_OK;
1564 return REG_REQ_ALREADY_SET;
1565 }
1566 return REG_REQ_OK;
1567}
1568
1584/** 1569/**
1585 * __regulatory_hint - hint to the wireless core a regulatory domain 1570 * reg_process_hint_country_ie - process regulatory requests from country IEs
1586 * @wiphy: if the hint comes from country information from an AP, this 1571 * @country_ie_request: a regulatory request from a country IE
1587 * is required to be set to the wiphy that received the information
1588 * @pending_request: the regulatory request currently being processed
1589 * 1572 *
1590 * The Wireless subsystem can use this function to hint to the wireless core 1573 * The wireless subsystem can use this function to process
1591 * what it believes should be the current regulatory domain. 1574 * a regulatory request issued by a country Information Element.
1592 * 1575 *
1593 * Returns one of the different reg request treatment values. 1576 * Returns one of the different reg request treatment values.
1594 */ 1577 */
1595static enum reg_request_treatment 1578static enum reg_request_treatment
1596__regulatory_hint(struct wiphy *wiphy, 1579reg_process_hint_country_ie(struct wiphy *wiphy,
1597 struct regulatory_request *pending_request) 1580 struct regulatory_request *country_ie_request)
1598{ 1581{
1599 const struct ieee80211_regdomain *regd;
1600 bool intersect = false;
1601 enum reg_request_treatment treatment; 1582 enum reg_request_treatment treatment;
1602 struct regulatory_request *lr; 1583 struct regulatory_request *lr;
1603 1584
1604 treatment = get_reg_request_treatment(wiphy, pending_request); 1585 treatment = __reg_process_hint_country_ie(wiphy, country_ie_request);
1605 1586
1606 switch (treatment) { 1587 switch (treatment) {
1607 case REG_REQ_INTERSECT:
1608 if (pending_request->initiator ==
1609 NL80211_REGDOM_SET_BY_DRIVER) {
1610 regd = reg_copy_regd(get_cfg80211_regdom());
1611 if (IS_ERR(regd)) {
1612 kfree(pending_request);
1613 return PTR_ERR(regd);
1614 }
1615 rcu_assign_pointer(wiphy->regd, regd);
1616 }
1617 intersect = true;
1618 break;
1619 case REG_REQ_OK: 1588 case REG_REQ_OK:
1620 break; 1589 break;
1621 default: 1590 case REG_REQ_IGNORE:
1591 /* fall through */
1592 case REG_REQ_ALREADY_SET:
1593 kfree(country_ie_request);
1594 return treatment;
1595 case REG_REQ_INTERSECT:
1596 kfree(country_ie_request);
1622 /* 1597 /*
1623 * If the regulatory domain being requested by the 1598 * This doesn't happen yet, not sure we
1624 * driver has already been set just copy it to the 1599 * ever want to support it for this case.
1625 * wiphy
1626 */ 1600 */
1627 if (treatment == REG_REQ_ALREADY_SET && 1601 WARN_ONCE(1, "Unexpected intersection for country IEs");
1628 pending_request->initiator == NL80211_REGDOM_SET_BY_DRIVER) { 1602 return REG_REQ_IGNORE;
1629 regd = reg_copy_regd(get_cfg80211_regdom());
1630 if (IS_ERR(regd)) {
1631 kfree(pending_request);
1632 return REG_REQ_IGNORE;
1633 }
1634 treatment = REG_REQ_ALREADY_SET;
1635 rcu_assign_pointer(wiphy->regd, regd);
1636 goto new_request;
1637 }
1638 kfree(pending_request);
1639 return treatment;
1640 } 1603 }
1641 1604
1642new_request:
1643 lr = get_last_request(); 1605 lr = get_last_request();
1644 if (lr != &core_request_world && lr) 1606 if (lr != &core_request_world && lr)
1645 kfree_rcu(lr, rcu_head); 1607 kfree_rcu(lr, rcu_head);
1646 1608
1647 pending_request->intersect = intersect; 1609 country_ie_request->intersect = false;
1648 pending_request->processed = false; 1610 country_ie_request->processed = false;
1649 rcu_assign_pointer(last_request, pending_request); 1611 rcu_assign_pointer(last_request, country_ie_request);
1650 lr = pending_request;
1651
1652 pending_request = NULL;
1653 1612
1654 if (lr->initiator == NL80211_REGDOM_SET_BY_USER) { 1613 if (call_crda(country_ie_request->alpha2))
1655 user_alpha2[0] = lr->alpha2[0];
1656 user_alpha2[1] = lr->alpha2[1];
1657 }
1658
1659 /* When r == REG_REQ_INTERSECT we do need to call CRDA */
1660 if (treatment != REG_REQ_OK && treatment != REG_REQ_INTERSECT) {
1661 /*
1662 * Since CRDA will not be called in this case as we already
1663 * have applied the requested regulatory domain before we just
1664 * inform userspace we have processed the request
1665 */
1666 if (treatment == REG_REQ_ALREADY_SET) {
1667 nl80211_send_reg_change_event(lr);
1668 reg_set_request_processed();
1669 }
1670 return treatment;
1671 }
1672
1673 if (call_crda(lr->alpha2))
1674 return REG_REQ_IGNORE; 1614 return REG_REQ_IGNORE;
1675 return REG_REQ_OK; 1615 return REG_REQ_OK;
1676} 1616}
@@ -1707,22 +1647,17 @@ static void reg_process_hint(struct regulatory_request *reg_request)
1707 treatment = reg_process_hint_driver(wiphy, reg_request); 1647 treatment = reg_process_hint_driver(wiphy, reg_request);
1708 break; 1648 break;
1709 case NL80211_REGDOM_SET_BY_COUNTRY_IE: 1649 case NL80211_REGDOM_SET_BY_COUNTRY_IE:
1710 treatment = __regulatory_hint(wiphy, reg_request); 1650 treatment = reg_process_hint_country_ie(wiphy, reg_request);
1711 break; 1651 break;
1712 default: 1652 default:
1713 WARN(1, "invalid initiator %d\n", reg_request->initiator); 1653 WARN(1, "invalid initiator %d\n", reg_request->initiator);
1714 return; 1654 return;
1715 } 1655 }
1716 1656
1717 switch (treatment) { 1657 /* This is required so that the orig_* parameters are saved */
1718 case REG_REQ_ALREADY_SET: 1658 if (treatment == REG_REQ_ALREADY_SET && wiphy &&
1719 /* This is required so that the orig_* parameters are saved */ 1659 wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY)
1720 if (wiphy && wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) 1660 wiphy_update_regulatory(wiphy, reg_request->initiator);
1721 wiphy_update_regulatory(wiphy, reg_request->initiator);
1722 break;
1723 default:
1724 break;
1725 }
1726} 1661}
1727 1662
1728/* 1663/*