mac80211: allow no mac address until firmware load
authorLuis Carlos Cobo <luisca@cozybit.com>
Thu, 14 Aug 2008 17:40:48 +0000 (10:40 -0700)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 22 Aug 2008 20:29:55 +0000 (16:29 -0400)
Originally by Johannes Berg. This patch adds support for devices that do not
report their MAC address until the firmware is loaded. While the address is not
known, a multicast on is used.

Signed-off-by: Luis Carlos Cobo <luisca@cozybit.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
net/mac80211/main.c

index f5537f90dd367f731a68cb78be17b2a30ae524ea..93dcdc27254b1a3861312aece96967ea58480c99 100644 (file)
@@ -187,9 +187,15 @@ static int ieee80211_open(struct net_device *dev)
        u32 changed = 0;
        int res;
        bool need_hw_reconfig = 0;
+       u8 null_addr[ETH_ALEN] = {0};
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
+       /* fail early if user set an invalid address */
+       if (compare_ether_addr(dev->dev_addr, null_addr) &&
+           !is_valid_ether_addr(dev->dev_addr))
+               return -EADDRNOTAVAIL;
+
        /* we hold the RTNL here so can safely walk the list */
        list_for_each_entry(nsdata, &local->interfaces, list) {
                struct net_device *ndev = nsdata->dev;
@@ -270,6 +276,36 @@ static int ieee80211_open(struct net_device *dev)
                ieee80211_led_radio(local, local->hw.conf.radio_enabled);
        }
 
+       /*
+        * Check all interfaces and copy the hopefully now-present
+        * MAC address to those that have the special null one.
+        */
+       list_for_each_entry(nsdata, &local->interfaces, list) {
+               struct net_device *ndev = nsdata->dev;
+
+               /*
+                * No need to check netif_running since we do not allow
+                * it to start up with this invalid address.
+                */
+               if (compare_ether_addr(null_addr, ndev->dev_addr) == 0)
+                       memcpy(ndev->dev_addr,
+                              local->hw.wiphy->perm_addr,
+                              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.
+        */
+       if (!is_valid_ether_addr(dev->dev_addr)) {
+               if (!local->open_count && local->ops->stop)
+                       local->ops->stop(local_to_hw(local));
+               return -EADDRNOTAVAIL;
+       }
+
        switch (sdata->vif.type) {
        case IEEE80211_IF_TYPE_VLAN:
                /* no need to tell driver */
@@ -975,6 +1011,8 @@ void ieee80211_if_setup(struct net_device *dev)
        dev->open = ieee80211_open;
        dev->stop = ieee80211_stop;
        dev->destructor = free_netdev;
+       /* we will validate the address ourselves in ->open */
+       dev->validate_addr = NULL;
 }
 
 /* everything else */