Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorJohn W. Linville <linville@tuxdriver.com>
Fri, 10 Jan 2014 15:59:40 +0000 (10:59 -0500)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 10 Jan 2014 15:59:40 +0000 (10:59 -0500)
Conflicts:
net/ieee802154/6lowpan.c

1  2 
drivers/net/wireless/adm8211.c
drivers/net/wireless/brcm80211/brcmfmac/p2p.c
drivers/net/wireless/hostap/hostap_ioctl.c
drivers/net/wireless/ipw2x00/libipw_rx.c
drivers/net/wireless/ti/wl1251/main.c
drivers/net/wireless/wl3501_cs.c
net/ipv6/addrconf.c
net/mac80211/iface.c

@@@ -15,7 -15,6 +15,6 @@@
   * more details.
   */
  
- #include <linux/init.h>
  #include <linux/interrupt.h>
  #include <linux/if.h>
  #include <linux/skbuff.h>
@@@ -1314,7 -1313,7 +1313,7 @@@ static void adm8211_bss_info_changed(st
        if (!(changes & BSS_CHANGED_BSSID))
                return;
  
 -      if (memcmp(conf->bssid, priv->bssid, ETH_ALEN)) {
 +      if (!ether_addr_equal(conf->bssid, priv->bssid)) {
                adm8211_set_bssid(dev, conf->bssid);
                memcpy(priv->bssid, conf->bssid, ETH_ALEN);
        }
@@@ -1243,7 -1243,7 +1243,7 @@@ bool brcmf_p2p_scan_finding_common_chan
                                            IEEE80211_P2P_ATTR_DEVICE_ID,
                                            p2p_dev_addr, sizeof(p2p_dev_addr));
        if ((err >= 0) &&
 -          (!memcmp(p2p_dev_addr, afx_hdl->tx_dst_addr, ETH_ALEN))) {
 +          (ether_addr_equal(p2p_dev_addr, afx_hdl->tx_dst_addr))) {
                if (!bi->ctl_ch) {
                        ch.chspec = le16_to_cpu(bi->chanspec);
                        cfg->d11inf.decchspec(&ch);
@@@ -1380,7 -1380,8 +1380,7 @@@ int brcmf_p2p_notify_action_frame_rx(st
                    (brcmf_p2p_gon_req_collision(p2p, (u8 *)e->addr))) {
                        if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,
                                     &p2p->status) &&
 -                          (memcmp(afx_hdl->tx_dst_addr, e->addr,
 -                                  ETH_ALEN) == 0)) {
 +                          (ether_addr_equal(afx_hdl->tx_dst_addr, e->addr))) {
                                afx_hdl->peer_chan = ch.chnum;
                                brcmf_dbg(INFO, "GON request: Peer found, channel=%d\n",
                                          afx_hdl->peer_chan);
@@@ -1864,7 -1865,7 +1864,7 @@@ s32 brcmf_p2p_notify_rx_mgmt_p2p_prober
        cfg->d11inf.decchspec(&ch);
  
        if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status) &&
 -          (memcmp(afx_hdl->tx_dst_addr, e->addr, ETH_ALEN) == 0)) {
 +          (ether_addr_equal(afx_hdl->tx_dst_addr, e->addr))) {
                afx_hdl->peer_chan = ch.chnum;
                brcmf_dbg(INFO, "PROBE REQUEST: Peer found, channel=%d\n",
                          afx_hdl->peer_chan);
@@@ -1955,21 -1956,21 +1955,21 @@@ s32 brcmf_p2p_attach(struct brcmf_cfg80
                err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1);
                if (err < 0) {
                        brcmf_err("set p2p_disc error\n");
-                       brcmf_free_vif(cfg, p2p_vif);
+                       brcmf_free_vif(p2p_vif);
                        goto exit;
                }
                /* obtain bsscfg index for P2P discovery */
                err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bssidx);
                if (err < 0) {
                        brcmf_err("retrieving discover bsscfg index failed\n");
-                       brcmf_free_vif(cfg, p2p_vif);
+                       brcmf_free_vif(p2p_vif);
                        goto exit;
                }
                /* Verify that firmware uses same bssidx as driver !! */
                if (p2p_ifp->bssidx != bssidx) {
                        brcmf_err("Incorrect bssidx=%d, compared to p2p_ifp->bssidx=%d\n",
                                  bssidx, p2p_ifp->bssidx);
-                       brcmf_free_vif(cfg, p2p_vif);
+                       brcmf_free_vif(p2p_vif);
                        goto exit;
                }
  
@@@ -1997,7 -1998,7 +1997,7 @@@ void brcmf_p2p_detach(struct brcmf_p2p_
                brcmf_p2p_cancel_remain_on_channel(vif->ifp);
                brcmf_p2p_deinit_discovery(p2p);
                /* remove discovery interface */
-               brcmf_free_vif(p2p->cfg, vif);
+               brcmf_free_vif(vif);
                p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
        }
        /* just set it all to zero */
@@@ -2222,7 -2223,7 +2222,7 @@@ static struct wireless_dev *brcmf_p2p_c
        return &p2p_vif->wdev;
  
  fail:
-       brcmf_free_vif(p2p->cfg, p2p_vif);
+       brcmf_free_vif(p2p_vif);
        return ERR_PTR(err);
  }
  
   *
   * @vif: virtual interface object to delete.
   */
- static void brcmf_p2p_delete_p2pdev(struct brcmf_cfg80211_info *cfg,
+ static void brcmf_p2p_delete_p2pdev(struct brcmf_p2p_info *p2p,
                                    struct brcmf_cfg80211_vif *vif)
  {
        cfg80211_unregister_wdev(&vif->wdev);
-       cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
-       brcmf_free_vif(cfg, vif);
- }
- /**
-  * brcmf_p2p_free_p2p_if() - free up net device related data.
-  *
-  * @ndev: net device that needs to be freed.
-  */
- static void brcmf_p2p_free_p2p_if(struct net_device *ndev)
- {
-       struct brcmf_cfg80211_info *cfg;
-       struct brcmf_cfg80211_vif *vif;
-       struct brcmf_if *ifp;
-       ifp = netdev_priv(ndev);
-       cfg = ifp->drvr->config;
-       vif = ifp->vif;
-       brcmf_free_vif(cfg, vif);
-       free_netdev(ifp->ndev);
+       p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
+       brcmf_free_vif(vif);
  }
  
  /**
@@@ -2335,8 -2317,6 +2316,6 @@@ struct wireless_dev *brcmf_p2p_add_vif(
                brcmf_err("Registering netdevice failed\n");
                goto fail;
        }
-       /* override destructor */
-       ifp->ndev->destructor = brcmf_p2p_free_p2p_if;
  
        cfg->p2p.bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = vif;
        /* Disable firmware roaming for P2P interface  */
        return &ifp->vif->wdev;
  
  fail:
-       brcmf_free_vif(cfg, vif);
+       brcmf_free_vif(vif);
        return ERR_PTR(err);
  }
  
   *
   * @wiphy: wiphy device of interface.
   * @wdev: wireless device of interface.
-  *
-  * TODO: not yet supported.
   */
  int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
  {
                break;
  
        case NL80211_IFTYPE_P2P_DEVICE:
-               brcmf_p2p_delete_p2pdev(cfg, vif);
+               brcmf_p2p_delete_p2pdev(p2p, vif);
                return 0;
        default:
                return -ENOTSUPP;
@@@ -655,7 -655,7 +655,7 @@@ static int hostap_join_ap(struct net_de
                if (!local->last_scan_results)
                        break;
                entry = &local->last_scan_results[i];
 -              if (memcmp(local->preferred_ap, entry->bssid, ETH_ALEN) == 0) {
 +              if (ether_addr_equal(local->preferred_ap, entry->bssid)) {
                        req.channel = entry->chid;
                        break;
                }
@@@ -1978,7 -1978,7 +1978,7 @@@ static inline int prism2_translate_scan
                list_for_each(ptr, &local->bss_list) {
                        struct hostap_bss_info *bss;
                        bss = list_entry(ptr, struct hostap_bss_info, list);
 -                      if (memcmp(bss->bssid, scan->bssid, ETH_ALEN) == 0) {
 +                      if (ether_addr_equal(bss->bssid, scan->bssid)) {
                                bss->included = 1;
                                current_ev = __prism2_translate_scan(
                                        local, info, scan, bss, current_ev,
@@@ -2567,7 -2567,7 +2567,7 @@@ static int prism2_ioctl_priv_prism2_par
                local->passive_scan_interval = value;
                if (timer_pending(&local->passive_scan_timer))
                        del_timer(&local->passive_scan_timer);
-               if (value > 0) {
+               if (value > 0 && value < INT_MAX / HZ) {
                        local->passive_scan_timer.expires = jiffies +
                                local->passive_scan_interval * HZ;
                        add_timer(&local->passive_scan_timer);
@@@ -874,13 -874,13 +874,13 @@@ void libipw_rx_any(struct libipw_devic
        switch (ieee->iw_mode) {
        case IW_MODE_ADHOC:
                /* our BSS and not from/to DS */
 -              if (memcmp(hdr->addr3, ieee->bssid, ETH_ALEN) == 0)
 +              if (ether_addr_equal(hdr->addr3, ieee->bssid))
                if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == 0) {
                        /* promisc: get all */
                        if (ieee->dev->flags & IFF_PROMISC)
                                is_packet_for_us = 1;
                        /* to us */
 -                      else if (memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN) == 0)
 +                      else if (ether_addr_equal(hdr->addr1, ieee->dev->dev_addr))
                                is_packet_for_us = 1;
                        /* mcast */
                        else if (is_multicast_ether_addr(hdr->addr1))
                break;
        case IW_MODE_INFRA:
                /* our BSS (== from our AP) and from DS */
 -              if (memcmp(hdr->addr2, ieee->bssid, ETH_ALEN) == 0)
 +              if (ether_addr_equal(hdr->addr2, ieee->bssid))
                if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_FROMDS) {
                        /* promisc: get all */
                        if (ieee->dev->flags & IFF_PROMISC)
                                is_packet_for_us = 1;
                        /* to us */
 -                      else if (memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN) == 0)
 +                      else if (ether_addr_equal(hdr->addr1, ieee->dev->dev_addr))
                                is_packet_for_us = 1;
                        /* mcast */
                        else if (is_multicast_ether_addr(hdr->addr1)) {
                                /* not our own packet bcasted from AP */
 -                              if (memcmp(hdr->addr3, ieee->dev->dev_addr, ETH_ALEN))
 +                              if (!ether_addr_equal(hdr->addr3, ieee->dev->dev_addr))
                                        is_packet_for_us = 1;
                        }
                }
@@@ -1468,7 -1468,7 +1468,7 @@@ static inline int is_same_network(struc
         * as one network */
        return ((src->ssid_len == dst->ssid_len) &&
                (src->channel == dst->channel) &&
-               ether_addr_equal(src->bssid, dst->bssid) &&
+               ether_addr_equal_64bits(src->bssid, dst->bssid) &&
                !memcmp(src->ssid, dst->ssid, src->ssid_len));
  }
  
@@@ -28,6 -28,7 +28,7 @@@
  #include <linux/etherdevice.h>
  #include <linux/vmalloc.h>
  #include <linux/slab.h>
+ #include <linux/netdevice.h>
  
  #include "wl1251.h"
  #include "wl12xx_80211.h"
@@@ -479,10 -480,13 +480,13 @@@ static void wl1251_op_stop(struct ieee8
        wl->next_tx_complete = 0;
        wl->elp = false;
        wl->station_mode = STATION_ACTIVE_MODE;
+       wl->psm_entry_retry = 0;
        wl->tx_queue_stopped = false;
        wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
        wl->rssi_thold = 0;
        wl->channel = WL1251_DEFAULT_CHANNEL;
+       wl->monitor_present = false;
+       wl->joined = false;
  
        wl1251_debugfs_reset(wl);
  
@@@ -521,7 -525,7 +525,7 @@@ static int wl1251_op_add_interface(stru
                goto out;
        }
  
 -      if (memcmp(wl->mac_addr, vif->addr, ETH_ALEN)) {
 +      if (!ether_addr_equal_unaligned(wl->mac_addr, vif->addr)) {
                memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
                SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
                ret = wl1251_acx_station_id(wl);
@@@ -542,6 -546,7 +546,7 @@@ static void wl1251_op_remove_interface(
        mutex_lock(&wl->mutex);
        wl1251_debug(DEBUG_MAC80211, "mac80211 remove interface");
        wl->vif = NULL;
+       memset(wl->bssid, 0, ETH_ALEN);
        mutex_unlock(&wl->mutex);
  }
  
@@@ -566,6 -571,11 +571,11 @@@ static int wl1251_build_qos_null_data(s
                                       sizeof(template));
  }
  
+ static bool wl1251_can_do_pm(struct ieee80211_conf *conf, struct wl1251 *wl)
+ {
+       return (conf->flags & IEEE80211_CONF_PS) && !wl->monitor_present;
+ }
  static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
  {
        struct wl1251 *wl = hw->priv;
        channel = ieee80211_frequency_to_channel(
                        conf->chandef.chan->center_freq);
  
-       wl1251_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
+       wl1251_debug(DEBUG_MAC80211,
+                    "mac80211 config ch %d monitor %s psm %s power %d",
                     channel,
+                    conf->flags & IEEE80211_CONF_MONITOR ? "on" : "off",
                     conf->flags & IEEE80211_CONF_PS ? "on" : "off",
                     conf->power_level);
  
        if (ret < 0)
                goto out;
  
+       if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
+               u32 mode;
+               if (conf->flags & IEEE80211_CONF_MONITOR) {
+                       wl->monitor_present = true;
+                       mode = DF_SNIFF_MODE_ENABLE | DF_ENCRYPTION_DISABLE;
+               } else {
+                       wl->monitor_present = false;
+                       mode = 0;
+               }
+               ret = wl1251_acx_feature_cfg(wl, mode);
+               if (ret < 0)
+                       goto out_sleep;
+       }
        if (channel != wl->channel) {
                wl->channel = channel;
  
-               ret = wl1251_join(wl, wl->bss_type, wl->channel,
-                                 wl->beacon_int, wl->dtim_period);
+               /*
+                * Use ENABLE_RX command for channel switching when no
+                * interface is present (monitor mode only).
+                * This leaves the tx path disabled in firmware, whereas
+                * the usual JOIN command seems to transmit some frames
+                * at firmware level.
+                */
+               if (wl->vif == NULL) {
+                       wl->joined = false;
+                       ret = wl1251_cmd_data_path_rx(wl, wl->channel, 1);
+               } else {
+                       ret = wl1251_join(wl, wl->bss_type, wl->channel,
+                                         wl->beacon_int, wl->dtim_period);
+               }
                if (ret < 0)
                        goto out_sleep;
        }
  
-       if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
+       if (wl1251_can_do_pm(conf, wl) && !wl->psm_requested) {
                wl1251_debug(DEBUG_PSM, "psm enabled");
  
                wl->psm_requested = true;
                ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
                if (ret < 0)
                        goto out_sleep;
-       } else if (!(conf->flags & IEEE80211_CONF_PS) &&
-                  wl->psm_requested) {
+       } else if (!wl1251_can_do_pm(conf, wl) && wl->psm_requested) {
                wl1251_debug(DEBUG_PSM, "psm disabled");
  
                wl->psm_requested = false;
                wl->power_level = conf->power_level;
        }
  
+       /*
+        * Tell stack that connection is lost because hw encryption isn't
+        * supported in monitor mode.
+        * This requires temporary enabling of the hw connection monitor flag
+        */
+       if ((changed & IEEE80211_CONF_CHANGE_MONITOR) && wl->vif) {
+               wl->hw->flags |= IEEE80211_HW_CONNECTION_MONITOR;
+               ieee80211_connection_loss(wl->vif);
+       }
  out_sleep:
        wl1251_ps_elp_sleep(wl);
  
@@@ -657,6 -706,44 +706,44 @@@ out
        return ret;
  }
  
+ struct wl1251_filter_params {
+       bool enabled;
+       int mc_list_length;
+       u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
+ };
+ static u64 wl1251_op_prepare_multicast(struct ieee80211_hw *hw,
+                                      struct netdev_hw_addr_list *mc_list)
+ {
+       struct wl1251_filter_params *fp;
+       struct netdev_hw_addr *ha;
+       struct wl1251 *wl = hw->priv;
+       if (unlikely(wl->state == WL1251_STATE_OFF))
+               return 0;
+       fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
+       if (!fp) {
+               wl1251_error("Out of memory setting filters.");
+               return 0;
+       }
+       /* update multicast filtering parameters */
+       fp->mc_list_length = 0;
+       if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
+               fp->enabled = false;
+       } else {
+               fp->enabled = true;
+               netdev_hw_addr_list_for_each(ha, mc_list) {
+                       memcpy(fp->mc_list[fp->mc_list_length],
+                                       ha->addr, ETH_ALEN);
+                       fp->mc_list_length++;
+               }
+       }
+       return (u64)(unsigned long)fp;
+ }
  #define WL1251_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
                                  FIF_ALLMULTI | \
                                  FIF_FCSFAIL | \
  
  static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
                                       unsigned int changed,
-                                      unsigned int *total,u64 multicast)
+                                      unsigned int *total, u64 multicast)
  {
+       struct wl1251_filter_params *fp = (void *)(unsigned long)multicast;
        struct wl1251 *wl = hw->priv;
        int ret;
  
        *total &= WL1251_SUPPORTED_FILTERS;
        changed &= WL1251_SUPPORTED_FILTERS;
  
-       if (changed == 0)
+       if (changed == 0) {
                /* no filters which we support changed */
+               kfree(fp);
                return;
+       }
  
        mutex_lock(&wl->mutex);
  
        if (ret < 0)
                goto out;
  
+       if (*total & FIF_ALLMULTI || *total & FIF_PROMISC_IN_BSS)
+               ret = wl1251_acx_group_address_tbl(wl, false, NULL, 0);
+       else if (fp)
+               ret = wl1251_acx_group_address_tbl(wl, fp->enabled,
+                                                  fp->mc_list,
+                                                  fp->mc_list_length);
+       if (ret < 0)
+               goto out;
        /* send filters to firmware */
        wl1251_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
  
  
  out:
        mutex_unlock(&wl->mutex);
+       kfree(fp);
  }
  
  /* HW encryption */
@@@ -802,12 -902,12 +902,12 @@@ static int wl1251_op_set_key(struct iee
  
        mutex_lock(&wl->mutex);
  
-       ret = wl1251_ps_elp_wakeup(wl);
-       if (ret < 0)
-               goto out_unlock;
        switch (cmd) {
        case SET_KEY:
+               if (wl->monitor_present) {
+                       ret = -EOPNOTSUPP;
+                       goto out_unlock;
+               }
                wl_cmd->key_action = KEY_ADD_OR_REPLACE;
                break;
        case DISABLE_KEY:
                break;
        }
  
+       ret = wl1251_ps_elp_wakeup(wl);
+       if (ret < 0)
+               goto out_unlock;
        ret = wl1251_set_key_type(wl, wl_cmd, cmd, key, addr);
        if (ret < 0) {
                wl1251_error("Set KEY type failed");
@@@ -930,6 -1034,7 +1034,7 @@@ static int wl1251_op_hw_scan(struct iee
        ret = wl1251_cmd_scan(wl, ssid, ssid_len, req->channels,
                              req->n_channels, WL1251_SCAN_NUM_PROBES);
        if (ret < 0) {
+               wl1251_debug(DEBUG_SCAN, "scan failed %d", ret);
                wl->scanning = false;
                goto out_idle;
        }
@@@ -977,6 -1082,7 +1082,7 @@@ static void wl1251_op_bss_info_changed(
  {
        struct wl1251 *wl = hw->priv;
        struct sk_buff *beacon, *skb;
+       bool enable;
        int ret;
  
        wl1251_debug(DEBUG_MAC80211, "mac80211 bss info changed");
        }
  
        if (changed & BSS_CHANGED_ASSOC) {
+               /* Disable temporary enabled hw connection monitor flag */
+               wl->hw->flags &= ~IEEE80211_HW_CONNECTION_MONITOR;
                if (bss_conf->assoc) {
                        wl->beacon_int = bss_conf->beacon_int;
  
                }
        }
  
+       if (changed & BSS_CHANGED_ARP_FILTER) {
+               __be32 addr = bss_conf->arp_addr_list[0];
+               WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
+               enable = bss_conf->arp_addr_cnt == 1 && bss_conf->assoc;
+               wl1251_acx_arp_ip_filter(wl, enable, addr);
+               if (ret < 0)
+                       goto out_sleep;
+       }
        if (changed & BSS_CHANGED_BEACON) {
                beacon = ieee80211_beacon_get(hw, vif);
                if (!beacon)
@@@ -1245,6 -1365,7 +1365,7 @@@ static const struct ieee80211_ops wl125
        .add_interface = wl1251_op_add_interface,
        .remove_interface = wl1251_op_remove_interface,
        .config = wl1251_op_config,
+       .prepare_multicast = wl1251_op_prepare_multicast,
        .configure_filter = wl1251_op_configure_filter,
        .tx = wl1251_op_tx,
        .set_key = wl1251_op_set_key,
@@@ -1401,7 -1522,10 +1522,10 @@@ struct ieee80211_hw *wl1251_alloc_hw(vo
  
        INIT_DELAYED_WORK(&wl->elp_work, wl1251_elp_work);
        wl->channel = WL1251_DEFAULT_CHANNEL;
+       wl->monitor_present = false;
+       wl->joined = false;
        wl->scanning = false;
+       wl->bss_type = MAX_BSS_TYPE;
        wl->default_key = 0;
        wl->listen_int = 1;
        wl->rx_counter = 0;
        wl->elp = false;
        wl->station_mode = STATION_ACTIVE_MODE;
        wl->psm_requested = false;
+       wl->psm_entry_retry = 0;
        wl->tx_queue_stopped = false;
        wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
        wl->rssi_thold = 0;
@@@ -1478,3 -1603,4 +1603,4 @@@ MODULE_DESCRIPTION("TI wl1251 Wireles L
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>");
  MODULE_FIRMWARE(WL1251_FW_NAME);
+ MODULE_FIRMWARE(WL1251_NVS_NAME);
@@@ -29,7 -29,6 +29,6 @@@
  
  #include <linux/delay.h>
  #include <linux/types.h>
- #include <linux/init.h>
  #include <linux/interrupt.h>
  #include <linux/in.h>
  #include <linux/kernel.h>
@@@ -44,7 -43,6 +43,7 @@@
  #include <linux/string.h>
  #include <linux/wireless.h>
  #include <linux/ieee80211.h>
 +#include <linux/etherdevice.h>
  
  #include <net/iw_handler.h>
  
@@@ -674,7 -672,8 +673,7 @@@ static void wl3501_mgmt_scan_confirm(st
                                matchflag = 1;
                        if (matchflag) {
                                for (i = 0; i < this->bss_cnt; i++) {
 -                                      if (!memcmp(this->bss_set[i].bssid,
 -                                                  sig.bssid, ETH_ALEN)) {
 +                                      if (ether_addr_equal_unaligned(this->bss_set[i].bssid, sig.bssid)) {
                                                matchflag = 0;
                                                break;
                                        }
diff --combined net/ipv6/addrconf.c
@@@ -442,8 -442,6 +442,8 @@@ static int inet6_netconf_msgsize_devcon
        if (type == -1 || type == NETCONFA_MC_FORWARDING)
                size += nla_total_size(4);
  #endif
 +      if (type == -1 || type == NETCONFA_PROXY_NEIGH)
 +              size += nla_total_size(4);
  
        return size;
  }
@@@ -477,10 -475,6 +477,10 @@@ static int inet6_netconf_fill_devconf(s
                        devconf->mc_forwarding) < 0)
                goto nla_put_failure;
  #endif
 +      if ((type == -1 || type == NETCONFA_PROXY_NEIGH) &&
 +          nla_put_s32(skb, NETCONFA_PROXY_NEIGH, devconf->proxy_ndp) < 0)
 +              goto nla_put_failure;
 +
        return nlmsg_end(skb, nlh);
  
  nla_put_failure:
@@@ -515,7 -509,6 +515,7 @@@ errout
  static const struct nla_policy devconf_ipv6_policy[NETCONFA_MAX+1] = {
        [NETCONFA_IFINDEX]      = { .len = sizeof(int) },
        [NETCONFA_FORWARDING]   = { .len = sizeof(int) },
 +      [NETCONFA_PROXY_NEIGH]  = { .len = sizeof(int) },
  };
  
  static int inet6_netconf_get_devconf(struct sk_buff *in_skb,
@@@ -841,8 -834,6 +841,8 @@@ ipv6_add_addr(struct inet6_dev *idev, c
                goto out;
        }
  
 +      neigh_parms_data_state_setall(idev->nd_parms);
 +
        ifa->addr = *addr;
        if (peer_addr)
                ifa->peer_addr = *peer_addr;
@@@ -995,9 -986,12 +995,9 @@@ static void ipv6_del_addr(struct inet6_
         * --yoshfuji
         */
        if ((ifp->flags & IFA_F_PERMANENT) && onlink < 1) {
 -              struct in6_addr prefix;
                struct rt6_info *rt;
  
 -              ipv6_addr_prefix(&prefix, &ifp->addr, ifp->prefix_len);
 -
 -              rt = addrconf_get_prefix_route(&prefix,
 +              rt = addrconf_get_prefix_route(&ifp->addr,
                                               ifp->prefix_len,
                                               ifp->idev->dev,
                                               0, RTF_GATEWAY | RTF_DEFAULT);
@@@ -1030,7 -1024,7 +1030,7 @@@ static int ipv6_create_tempaddr(struct 
        u32 addr_flags;
        unsigned long now = jiffies;
  
 -      write_lock(&idev->lock);
 +      write_lock_bh(&idev->lock);
        if (ift) {
                spin_lock_bh(&ift->lock);
                memcpy(&addr.s6_addr[8], &ift->addr.s6_addr[8], 8);
  retry:
        in6_dev_hold(idev);
        if (idev->cnf.use_tempaddr <= 0) {
 -              write_unlock(&idev->lock);
 +              write_unlock_bh(&idev->lock);
                pr_info("%s: use_tempaddr is disabled\n", __func__);
                in6_dev_put(idev);
                ret = -1;
        if (ifp->regen_count++ >= idev->cnf.regen_max_retry) {
                idev->cnf.use_tempaddr = -1;    /*XXX*/
                spin_unlock_bh(&ifp->lock);
 -              write_unlock(&idev->lock);
 +              write_unlock_bh(&idev->lock);
                pr_warn("%s: regeneration time exceeded - disabled temporary address support\n",
                        __func__);
                in6_dev_put(idev);
  
        regen_advance = idev->cnf.regen_max_retry *
                        idev->cnf.dad_transmits *
 -                      idev->nd_parms->retrans_time / HZ;
 -      write_unlock(&idev->lock);
 +                      NEIGH_VAR(idev->nd_parms, RETRANS_TIME) / HZ;
 +      write_unlock_bh(&idev->lock);
  
        /* A temporary address is created only if this calculated Preferred
         * Lifetime is greater than REGEN_ADVANCE time units.  In particular,
                in6_dev_put(idev);
                pr_info("%s: retry temporary address regeneration\n", __func__);
                tmpaddr = &addr;
 -              write_lock(&idev->lock);
 +              write_lock_bh(&idev->lock);
                goto retry;
        }
  
@@@ -1413,7 -1407,7 +1413,7 @@@ try_nextdev
  EXPORT_SYMBOL(ipv6_dev_get_saddr);
  
  int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr,
 -                    unsigned char banned_flags)
 +                    u32 banned_flags)
  {
        struct inet6_ifaddr *ifp;
        int err = -EADDRNOTAVAIL;
  }
  
  int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
 -                  unsigned char banned_flags)
 +                  u32 banned_flags)
  {
        struct inet6_dev *idev;
        int err = -EADDRNOTAVAIL;
@@@ -1677,7 -1671,7 +1677,7 @@@ void addrconf_leave_solict(struct inet6
  static void addrconf_join_anycast(struct inet6_ifaddr *ifp)
  {
        struct in6_addr addr;
 -      if (ifp->prefix_len == 127) /* RFC 6164 */
 +      if (ifp->prefix_len >= 127) /* RFC 6164 */
                return;
        ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len);
        if (ipv6_addr_any(&addr))
  static void addrconf_leave_anycast(struct inet6_ifaddr *ifp)
  {
        struct in6_addr addr;
 -      if (ifp->prefix_len == 127) /* RFC 6164 */
 +      if (ifp->prefix_len >= 127) /* RFC 6164 */
                return;
        ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len);
        if (ipv6_addr_any(&addr))
@@@ -1822,6 -1816,7 +1822,7 @@@ static int ipv6_generate_eui64(u8 *eui
                return addrconf_ifid_sit(eui, dev);
        case ARPHRD_IPGRE:
                return addrconf_ifid_gre(eui, dev);
+       case ARPHRD_6LOWPAN:
        case ARPHRD_IEEE802154:
                return addrconf_ifid_eui64(eui, dev);
        case ARPHRD_IEEE1394:
@@@ -1894,8 -1889,7 +1895,8 @@@ static void ipv6_regen_rndid(unsigned l
  
        expires = jiffies +
                idev->cnf.temp_prefered_lft * HZ -
 -              idev->cnf.regen_max_retry * idev->cnf.dad_transmits * idev->nd_parms->retrans_time -
 +              idev->cnf.regen_max_retry * idev->cnf.dad_transmits *
 +              NEIGH_VAR(idev->nd_parms, RETRANS_TIME) -
                idev->cnf.max_desync_factor * HZ;
        if (time_before(expires, jiffies)) {
                pr_warn("%s: too short regeneration interval; timer disabled for %s\n",
@@@ -2023,73 -2017,6 +2024,73 @@@ static struct inet6_dev *addrconf_add_d
        return idev;
  }
  
 +static void manage_tempaddrs(struct inet6_dev *idev,
 +                           struct inet6_ifaddr *ifp,
 +                           __u32 valid_lft, __u32 prefered_lft,
 +                           bool create, unsigned long now)
 +{
 +      u32 flags;
 +      struct inet6_ifaddr *ift;
 +
 +      read_lock_bh(&idev->lock);
 +      /* update all temporary addresses in the list */
 +      list_for_each_entry(ift, &idev->tempaddr_list, tmp_list) {
 +              int age, max_valid, max_prefered;
 +
 +              if (ifp != ift->ifpub)
 +                      continue;
 +
 +              /* RFC 4941 section 3.3:
 +               * If a received option will extend the lifetime of a public
 +               * address, the lifetimes of temporary addresses should
 +               * be extended, subject to the overall constraint that no
 +               * temporary addresses should ever remain "valid" or "preferred"
 +               * for a time longer than (TEMP_VALID_LIFETIME) or
 +               * (TEMP_PREFERRED_LIFETIME - DESYNC_FACTOR), respectively.
 +               */
 +              age = (now - ift->cstamp) / HZ;
 +              max_valid = idev->cnf.temp_valid_lft - age;
 +              if (max_valid < 0)
 +                      max_valid = 0;
 +
 +              max_prefered = idev->cnf.temp_prefered_lft -
 +                             idev->cnf.max_desync_factor - age;
 +              if (max_prefered < 0)
 +                      max_prefered = 0;
 +
 +              if (valid_lft > max_valid)
 +                      valid_lft = max_valid;
 +
 +              if (prefered_lft > max_prefered)
 +                      prefered_lft = max_prefered;
 +
 +              spin_lock(&ift->lock);
 +              flags = ift->flags;
 +              ift->valid_lft = valid_lft;
 +              ift->prefered_lft = prefered_lft;
 +              ift->tstamp = now;
 +              if (prefered_lft > 0)
 +                      ift->flags &= ~IFA_F_DEPRECATED;
 +
 +              spin_unlock(&ift->lock);
 +              if (!(flags&IFA_F_TENTATIVE))
 +                      ipv6_ifa_notify(0, ift);
 +      }
 +
 +      if ((create || list_empty(&idev->tempaddr_list)) &&
 +          idev->cnf.use_tempaddr > 0) {
 +              /* When a new public address is created as described
 +               * in [ADDRCONF], also create a new temporary address.
 +               * Also create a temporary address if it's enabled but
 +               * no temporary address currently exists.
 +               */
 +              read_unlock_bh(&idev->lock);
 +              ipv6_create_tempaddr(ifp, NULL);
 +      } else {
 +              read_unlock_bh(&idev->lock);
 +      }
 +}
 +
  void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
  {
        struct prefix_info *pinfo;
@@@ -2244,7 -2171,6 +2245,7 @@@ ok
                                return;
                        }
  
 +                      ifp->flags |= IFA_F_MANAGETEMPADDR;
                        update_lft = 0;
                        create = 1;
                        ifp->cstamp = jiffies;
                }
  
                if (ifp) {
 -                      int flags;
 +                      u32 flags;
                        unsigned long now;
 -                      struct inet6_ifaddr *ift;
                        u32 stored_lft;
  
                        /* update lifetime (RFC2462 5.5.3 e) */
                        } else
                                spin_unlock(&ifp->lock);
  
 -                      read_lock_bh(&in6_dev->lock);
 -                      /* update all temporary addresses in the list */
 -                      list_for_each_entry(ift, &in6_dev->tempaddr_list,
 -                                          tmp_list) {
 -                              int age, max_valid, max_prefered;
 -
 -                              if (ifp != ift->ifpub)
 -                                      continue;
 -
 -                              /*
 -                               * RFC 4941 section 3.3:
 -                               * If a received option will extend the lifetime
 -                               * of a public address, the lifetimes of
 -                               * temporary addresses should be extended,
 -                               * subject to the overall constraint that no
 -                               * temporary addresses should ever remain
 -                               * "valid" or "preferred" for a time longer than
 -                               * (TEMP_VALID_LIFETIME) or
 -                               * (TEMP_PREFERRED_LIFETIME - DESYNC_FACTOR),
 -                               * respectively.
 -                               */
 -                              age = (now - ift->cstamp) / HZ;
 -                              max_valid = in6_dev->cnf.temp_valid_lft - age;
 -                              if (max_valid < 0)
 -                                      max_valid = 0;
 -
 -                              max_prefered = in6_dev->cnf.temp_prefered_lft -
 -                                             in6_dev->cnf.max_desync_factor -
 -                                             age;
 -                              if (max_prefered < 0)
 -                                      max_prefered = 0;
 -
 -                              if (valid_lft > max_valid)
 -                                      valid_lft = max_valid;
 -
 -                              if (prefered_lft > max_prefered)
 -                                      prefered_lft = max_prefered;
 -
 -                              spin_lock(&ift->lock);
 -                              flags = ift->flags;
 -                              ift->valid_lft = valid_lft;
 -                              ift->prefered_lft = prefered_lft;
 -                              ift->tstamp = now;
 -                              if (prefered_lft > 0)
 -                                      ift->flags &= ~IFA_F_DEPRECATED;
 -
 -                              spin_unlock(&ift->lock);
 -                              if (!(flags&IFA_F_TENTATIVE))
 -                                      ipv6_ifa_notify(0, ift);
 -                      }
 -
 -                      if ((create || list_empty(&in6_dev->tempaddr_list)) && in6_dev->cnf.use_tempaddr > 0) {
 -                              /*
 -                               * When a new public address is created as
 -                               * described in [ADDRCONF], also create a new
 -                               * temporary address. Also create a temporary
 -                               * address if it's enabled but no temporary
 -                               * address currently exists.
 -                               */
 -                              read_unlock_bh(&in6_dev->lock);
 -                              ipv6_create_tempaddr(ifp, NULL);
 -                      } else {
 -                              read_unlock_bh(&in6_dev->lock);
 -                      }
 +                      manage_tempaddrs(in6_dev, ifp, valid_lft, prefered_lft,
 +                                       create, now);
  
                        in6_ifa_put(ifp);
                        addrconf_verify(0);
@@@ -2375,11 -2364,10 +2376,11 @@@ err_exit
  /*
   *    Manual configuration of address on an interface
   */
 -static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *pfx,
 +static int inet6_addr_add(struct net *net, int ifindex,
 +                        const struct in6_addr *pfx,
                          const struct in6_addr *peer_pfx,
 -                        unsigned int plen, __u8 ifa_flags, __u32 prefered_lft,
 -                        __u32 valid_lft)
 +                        unsigned int plen, __u32 ifa_flags,
 +                        __u32 prefered_lft, __u32 valid_lft)
  {
        struct inet6_ifaddr *ifp;
        struct inet6_dev *idev;
        if (!valid_lft || prefered_lft > valid_lft)
                return -EINVAL;
  
 +      if (ifa_flags & IFA_F_MANAGETEMPADDR && plen != 64)
 +              return -EINVAL;
 +
        dev = __dev_get_by_index(net, ifindex);
        if (!dev)
                return -ENODEV;
                 * manually configured addresses
                 */
                addrconf_dad_start(ifp);
 +              if (ifa_flags & IFA_F_MANAGETEMPADDR)
 +                      manage_tempaddrs(idev, ifp, valid_lft, prefered_lft,
 +                                       true, jiffies);
                in6_ifa_put(ifp);
                addrconf_verify(0);
                return 0;
@@@ -2632,7 -2614,7 +2633,7 @@@ static void init_loopback(struct net_de
                        if (sp_ifa->rt)
                                continue;
  
 -                      sp_rt = addrconf_dst_alloc(idev, &sp_ifa->addr, 0);
 +                      sp_rt = addrconf_dst_alloc(idev, &sp_ifa->addr, false);
  
                        /* Failure cases are ignored */
                        if (!IS_ERR(sp_rt)) {
@@@ -2677,7 -2659,8 +2678,8 @@@ static void addrconf_dev_config(struct 
            (dev->type != ARPHRD_INFINIBAND) &&
            (dev->type != ARPHRD_IEEE802154) &&
            (dev->type != ARPHRD_IEEE1394) &&
-           (dev->type != ARPHRD_TUNNEL6)) {
+           (dev->type != ARPHRD_TUNNEL6) &&
+           (dev->type != ARPHRD_6LOWPAN)) {
                /* Alas, we support only Ethernet autoconfiguration. */
                return;
        }
@@@ -3195,8 -3178,7 +3197,8 @@@ static void addrconf_dad_timer(unsigne
        }
  
        ifp->dad_probes--;
 -      addrconf_mod_dad_timer(ifp, ifp->idev->nd_parms->retrans_time);
 +      addrconf_mod_dad_timer(ifp,
 +                             NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME));
        spin_unlock(&ifp->lock);
        write_unlock(&idev->lock);
  
@@@ -3376,7 -3358,7 +3378,7 @@@ static int if6_seq_show(struct seq_fil
                   ifp->idev->dev->ifindex,
                   ifp->prefix_len,
                   ifp->scope,
 -                 ifp->flags,
 +                 (u8) ifp->flags,
                   ifp->idev->dev->name);
        return 0;
  }
@@@ -3476,12 -3458,7 +3478,12 @@@ restart
                                         &inet6_addr_lst[i], addr_lst) {
                        unsigned long age;
  
 -                      if (ifp->flags & IFA_F_PERMANENT)
 +                      /* When setting preferred_lft to a value not zero or
 +                       * infinity, while valid_lft is infinity
 +                       * IFA_F_PERMANENT has a non-infinity life time.
 +                       */
 +                      if ((ifp->flags & IFA_F_PERMANENT) &&
 +                          (ifp->prefered_lft == INFINITY_LIFE_TIME))
                                continue;
  
                        spin_lock(&ifp->lock);
                                        ifp->flags |= IFA_F_DEPRECATED;
                                }
  
 -                              if (time_before(ifp->tstamp + ifp->valid_lft * HZ, next))
 +                              if ((ifp->valid_lft != INFINITY_LIFE_TIME) &&
 +                                  (time_before(ifp->tstamp + ifp->valid_lft * HZ, next)))
                                        next = ifp->tstamp + ifp->valid_lft * HZ;
  
                                spin_unlock(&ifp->lock);
                                   !(ifp->flags&IFA_F_TENTATIVE)) {
                                unsigned long regen_advance = ifp->idev->cnf.regen_max_retry *
                                        ifp->idev->cnf.dad_transmits *
 -                                      ifp->idev->nd_parms->retrans_time / HZ;
 +                                      NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME) / HZ;
  
                                if (age >= ifp->prefered_lft - regen_advance) {
                                        struct inet6_ifaddr *ifpub = ifp->ifpub;
@@@ -3598,7 -3574,6 +3600,7 @@@ static const struct nla_policy ifa_ipv6
        [IFA_ADDRESS]           = { .len = sizeof(struct in6_addr) },
        [IFA_LOCAL]             = { .len = sizeof(struct in6_addr) },
        [IFA_CACHEINFO]         = { .len = sizeof(struct ifa_cacheinfo) },
 +      [IFA_FLAGS]             = { .len = sizeof(u32) },
  };
  
  static int
@@@ -3622,21 -3597,16 +3624,21 @@@ inet6_rtm_deladdr(struct sk_buff *skb, 
        return inet6_addr_del(net, ifm->ifa_index, pfx, ifm->ifa_prefixlen);
  }
  
 -static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags,
 +static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags,
                             u32 prefered_lft, u32 valid_lft)
  {
        u32 flags;
        clock_t expires;
        unsigned long timeout;
 +      bool was_managetempaddr;
  
        if (!valid_lft || (prefered_lft > valid_lft))
                return -EINVAL;
  
 +      if (ifa_flags & IFA_F_MANAGETEMPADDR &&
 +          (ifp->flags & IFA_F_TEMPORARY || ifp->prefix_len != 64))
 +              return -EINVAL;
 +
        timeout = addrconf_timeout_fixup(valid_lft, HZ);
        if (addrconf_finite_timeout(timeout)) {
                expires = jiffies_to_clock_t(timeout * HZ);
        }
  
        spin_lock_bh(&ifp->lock);
 -      ifp->flags = (ifp->flags & ~(IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_NODAD | IFA_F_HOMEADDRESS)) | ifa_flags;
 +      was_managetempaddr = ifp->flags & IFA_F_MANAGETEMPADDR;
 +      ifp->flags &= ~(IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_NODAD |
 +                      IFA_F_HOMEADDRESS | IFA_F_MANAGETEMPADDR);
 +      ifp->flags |= ifa_flags;
        ifp->tstamp = jiffies;
        ifp->valid_lft = valid_lft;
        ifp->prefered_lft = prefered_lft;
  
        addrconf_prefix_route(&ifp->addr, ifp->prefix_len, ifp->idev->dev,
                              expires, flags);
 +
 +      if (was_managetempaddr || ifp->flags & IFA_F_MANAGETEMPADDR) {
 +              if (was_managetempaddr && !(ifp->flags & IFA_F_MANAGETEMPADDR))
 +                      valid_lft = prefered_lft = 0;
 +              manage_tempaddrs(ifp->idev, ifp, valid_lft, prefered_lft,
 +                               !was_managetempaddr, jiffies);
 +      }
 +
        addrconf_verify(0);
  
        return 0;
@@@ -3693,7 -3652,7 +3695,7 @@@ inet6_rtm_newaddr(struct sk_buff *skb, 
        struct inet6_ifaddr *ifa;
        struct net_device *dev;
        u32 valid_lft = INFINITY_LIFE_TIME, preferred_lft = INFINITY_LIFE_TIME;
 -      u8 ifa_flags;
 +      u32 ifa_flags;
        int err;
  
        err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy);
        if (dev == NULL)
                return -ENODEV;
  
 +      ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) : ifm->ifa_flags;
 +
        /* We ignore other flags so far. */
 -      ifa_flags = ifm->ifa_flags & (IFA_F_NODAD | IFA_F_HOMEADDRESS);
 +      ifa_flags &= IFA_F_NODAD | IFA_F_HOMEADDRESS | IFA_F_MANAGETEMPADDR;
  
        ifa = ipv6_get_ifaddr(net, pfx, dev, 1);
        if (ifa == NULL) {
        return err;
  }
  
 -static void put_ifaddrmsg(struct nlmsghdr *nlh, u8 prefixlen, u8 flags,
 +static void put_ifaddrmsg(struct nlmsghdr *nlh, u8 prefixlen, u32 flags,
                          u8 scope, int ifindex)
  {
        struct ifaddrmsg *ifm;
@@@ -3790,8 -3747,7 +3792,8 @@@ static inline int inet6_ifaddr_msgsize(
        return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
               + nla_total_size(16) /* IFA_LOCAL */
               + nla_total_size(16) /* IFA_ADDRESS */
 -             + nla_total_size(sizeof(struct ifa_cacheinfo));
 +             + nla_total_size(sizeof(struct ifa_cacheinfo))
 +             + nla_total_size(4)  /* IFA_FLAGS */;
  }
  
  static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,
        put_ifaddrmsg(nlh, ifa->prefix_len, ifa->flags, rt_scope(ifa->scope),
                      ifa->idev->dev->ifindex);
  
 -      if (!(ifa->flags&IFA_F_PERMANENT)) {
 +      if (!((ifa->flags&IFA_F_PERMANENT) &&
 +            (ifa->prefered_lft == INFINITY_LIFE_TIME))) {
                preferred = ifa->prefered_lft;
                valid = ifa->valid_lft;
                if (preferred != INFINITY_LIFE_TIME) {
        if (put_cacheinfo(skb, ifa->cstamp, ifa->tstamp, preferred, valid) < 0)
                goto error;
  
 +      if (nla_put_u32(skb, IFA_FLAGS, ifa->flags) < 0)
 +              goto error;
 +
        return nlmsg_end(skb, nlh);
  
  error:
@@@ -4246,7 -4198,7 +4248,7 @@@ static int inet6_fill_ifla6_attrs(struc
        ci.max_reasm_len = IPV6_MAXPLEN;
        ci.tstamp = cstamp_delta(idev->tstamp);
        ci.reachable_time = jiffies_to_msecs(idev->nd_parms->reachable_time);
 -      ci.retrans_time = jiffies_to_msecs(idev->nd_parms->retrans_time);
 +      ci.retrans_time = jiffies_to_msecs(NEIGH_VAR(idev->nd_parms, RETRANS_TIME));
        if (nla_put(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci))
                goto nla_put_failure;
        nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32));
@@@ -4739,46 -4691,6 +4741,46 @@@ int addrconf_sysctl_disable(struct ctl_
        return ret;
  }
  
 +static
 +int addrconf_sysctl_proxy_ndp(struct ctl_table *ctl, int write,
 +                            void __user *buffer, size_t *lenp, loff_t *ppos)
 +{
 +      int *valp = ctl->data;
 +      int ret;
 +      int old, new;
 +
 +      old = *valp;
 +      ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
 +      new = *valp;
 +
 +      if (write && old != new) {
 +              struct net *net = ctl->extra2;
 +
 +              if (!rtnl_trylock())
 +                      return restart_syscall();
 +
 +              if (valp == &net->ipv6.devconf_dflt->proxy_ndp)
 +                      inet6_netconf_notify_devconf(net, NETCONFA_PROXY_NEIGH,
 +                                                   NETCONFA_IFINDEX_DEFAULT,
 +                                                   net->ipv6.devconf_dflt);
 +              else if (valp == &net->ipv6.devconf_all->proxy_ndp)
 +                      inet6_netconf_notify_devconf(net, NETCONFA_PROXY_NEIGH,
 +                                                   NETCONFA_IFINDEX_ALL,
 +                                                   net->ipv6.devconf_all);
 +              else {
 +                      struct inet6_dev *idev = ctl->extra1;
 +
 +                      inet6_netconf_notify_devconf(net, NETCONFA_PROXY_NEIGH,
 +                                                   idev->dev->ifindex,
 +                                                   &idev->cnf);
 +              }
 +              rtnl_unlock();
 +      }
 +
 +      return ret;
 +}
 +
 +
  static struct addrconf_sysctl_table
  {
        struct ctl_table_header *sysctl_header;
                        .data           = &ipv6_devconf.proxy_ndp,
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
 -                      .proc_handler   = proc_dointvec,
 +                      .proc_handler   = addrconf_sysctl_proxy_ndp,
                },
                {
                        .procname       = "accept_source_route",
@@@ -5081,7 -4993,7 +5083,7 @@@ static void __addrconf_sysctl_unregiste
  
  static void addrconf_sysctl_register(struct inet6_dev *idev)
  {
 -      neigh_sysctl_register(idev->dev, idev->nd_parms, "ipv6",
 +      neigh_sysctl_register(idev->dev, idev->nd_parms,
                              &ndisc_ifinfo_sysctl_change);
        __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name,
                                        idev, &idev->cnf);
@@@ -5214,7 -5126,9 +5216,7 @@@ int __init addrconf_init(void
  
        addrconf_verify(0);
  
 -      err = rtnl_af_register(&inet6_ops);
 -      if (err < 0)
 -              goto errout_af;
 +      rtnl_af_register(&inet6_ops);
  
        err = __rtnl_register(PF_INET6, RTM_GETLINK, NULL, inet6_dump_ifinfo,
                              NULL);
        return 0;
  errout:
        rtnl_af_unregister(&inet6_ops);
 -errout_af:
        unregister_netdevice_notifier(&ipv6_dev_notf);
  errlo:
        unregister_pernet_subsys(&addrconf_ops);
diff --combined net/mac80211/iface.c
@@@ -418,8 -418,10 +418,10 @@@ int ieee80211_add_virtual_monitor(struc
                return ret;
        }
  
+       mutex_lock(&local->mtx);
        ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef,
                                        IEEE80211_CHANCTX_EXCLUSIVE);
+       mutex_unlock(&local->mtx);
        if (ret) {
                drv_remove_interface(local, sdata);
                kfree(sdata);
@@@ -456,7 -458,9 +458,9 @@@ void ieee80211_del_virtual_monitor(stru
  
        synchronize_net();
  
+       mutex_lock(&local->mtx);
        ieee80211_vif_release_channel(sdata);
+       mutex_unlock(&local->mtx);
  
        drv_remove_interface(local, sdata);
  
@@@ -826,9 -830,9 +830,9 @@@ static void ieee80211_do_stop(struct ie
        if (sdata->wdev.cac_started) {
                chandef = sdata->vif.bss_conf.chandef;
                WARN_ON(local->suspended);
-               mutex_lock(&local->iflist_mtx);
+               mutex_lock(&local->mtx);
                ieee80211_vif_release_channel(sdata);
-               mutex_unlock(&local->iflist_mtx);
+               mutex_unlock(&local->mtx);
                cfg80211_cac_event(sdata->dev, &chandef,
                                   NL80211_RADAR_CAC_ABORTED,
                                   GFP_KERNEL);
@@@ -1476,8 -1480,8 +1480,8 @@@ static void ieee80211_assign_perm_addr(
                        bool used = false;
  
                        list_for_each_entry(sdata, &local->interfaces, list) {
 -                              if (memcmp(local->hw.wiphy->addresses[i].addr,
 -                                         sdata->vif.addr, ETH_ALEN) == 0) {
 +                              if (ether_addr_equal(local->hw.wiphy->addresses[i].addr,
 +                                                   sdata->vif.addr)) {
                                        used = true;
                                        break;
                                }
                        val += inc;
  
                        list_for_each_entry(sdata, &local->interfaces, list) {
 -                              if (memcmp(tmp_addr, sdata->vif.addr,
 -                                                      ETH_ALEN) == 0) {
 +                              if (ether_addr_equal(tmp_addr, sdata->vif.addr)) {
                                        used = true;
                                        break;
                                }