cfg80211: implement IWAP for WDS
Johannes Berg [Wed, 1 Jul 2009 19:26:58 +0000 (21:26 +0200)]
This implements siocsiwap/giwap for WDS mode.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

include/net/cfg80211.h
net/mac80211/cfg.c
net/mac80211/wext.c
net/wireless/wext-compat.c

index 82b7d80..b396d11 100644 (file)
@@ -1018,6 +1018,9 @@ struct cfg80211_ops {
                                enum tx_power_setting type, int dbm);
        int     (*get_tx_power)(struct wiphy *wiphy, int *dbm);
 
+       int     (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev,
+                               u8 *addr);
+
        void    (*rfkill_poll)(struct wiphy *wiphy);
 
 #ifdef CONFIG_NL80211_TESTMODE
@@ -1619,6 +1622,13 @@ int cfg80211_wext_giwpower(struct net_device *dev,
                           struct iw_request_info *info,
                           struct iw_param *wrq, char *extra);
 
+int cfg80211_wds_wext_siwap(struct net_device *dev,
+                           struct iw_request_info *info,
+                           struct sockaddr *addr, char *extra);
+int cfg80211_wds_wext_giwap(struct net_device *dev,
+                           struct iw_request_info *info,
+                           struct sockaddr *addr, char *extra);
+
 /*
  * callbacks for asynchronous cfg80211 methods, notification
  * functions and BSS handling helpers
index 8c7b2cd..2cf5bf6 100644 (file)
@@ -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,
index f779298..4053d76 100644 (file)
@@ -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;
 }
index 2e1ab78..2f72dae 100644 (file)
@@ -1047,3 +1047,49 @@ int cfg80211_wext_giwpower(struct net_device *dev,
        return 0;
 }
 EXPORT_SYMBOL_GPL(cfg80211_wext_giwpower);
+
+int cfg80211_wds_wext_siwap(struct net_device *dev,
+                           struct iw_request_info *info,
+                           struct sockaddr *addr, char *extra)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       int err;
+
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_WDS))
+               return -EINVAL;
+
+       if (addr->sa_family != ARPHRD_ETHER)
+               return -EINVAL;
+
+       if (netif_running(dev))
+               return -EBUSY;
+
+       if (!rdev->ops->set_wds_peer)
+               return -EOPNOTSUPP;
+
+       err = rdev->ops->set_wds_peer(wdev->wiphy, dev, (u8 *) &addr->sa_data);
+       if (err)
+               return err;
+
+       memcpy(&wdev->wext.bssid, (u8 *) &addr->sa_data, ETH_ALEN);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(cfg80211_wds_wext_siwap);
+
+int cfg80211_wds_wext_giwap(struct net_device *dev,
+                           struct iw_request_info *info,
+                           struct sockaddr *addr, char *extra)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_WDS))
+               return -EINVAL;
+
+       addr->sa_family = ARPHRD_ETHER;
+       memcpy(&addr->sa_data, wdev->wext.bssid, ETH_ALEN);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(cfg80211_wds_wext_giwap);