mac80211: backport brcmfmac patchset with driver setting concept
[openwrt.git] / package / kernel / mac80211 / patches / 344-0006-brcmfmac-add-neighbor-discovery-offload-ip-address-t.patch
1 From: Franky Lin <frankyl@broadcom.com>
2 Date: Wed, 17 Feb 2016 11:26:55 +0100
3 Subject: [PATCH] brcmfmac: add neighbor discovery offload ip address table
4  configuration
5
6 Configure ipv6 address for neighbor discovery offload ip table in
7 firmware obtained through ipv6 address notification callback.
8
9 Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
10 Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
11 Signed-off-by: Franky Lin <frankyl@broadcom.com>
12 Signed-off-by: Arend van Spriel <arend@broadcom.com>
13 Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
14 ---
15
16 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
17 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
18 @@ -456,7 +456,7 @@ send_key_to_dongle(struct brcmf_if *ifp,
19  }
20  
21  static s32
22 -brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable)
23 +brcmf_configure_arp_nd_offload(struct brcmf_if *ifp, bool enable)
24  {
25         s32 err;
26         u32 mode;
27 @@ -484,6 +484,15 @@ brcmf_configure_arp_offload(struct brcmf
28                                   enable, mode);
29         }
30  
31 +       err = brcmf_fil_iovar_int_set(ifp, "ndoe", enable);
32 +       if (err) {
33 +               brcmf_dbg(TRACE, "failed to configure (%d) ND offload err = %d\n",
34 +                         enable, err);
35 +               err = 0;
36 +       } else
37 +               brcmf_dbg(TRACE, "successfully configured (%d) ND offload to 0x%x\n",
38 +                         enable, mode);
39 +
40         return err;
41  }
42  
43 @@ -3543,7 +3552,7 @@ static s32 brcmf_cfg80211_resume(struct
44                 brcmf_report_wowl_wakeind(wiphy, ifp);
45                 brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
46                 brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
47 -               brcmf_configure_arp_offload(ifp, true);
48 +               brcmf_configure_arp_nd_offload(ifp, true);
49                 brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
50                                       cfg->wowl.pre_pmmode);
51                 cfg->wowl.active = false;
52 @@ -3567,7 +3576,7 @@ static void brcmf_configure_wowl(struct
53  
54         brcmf_dbg(TRACE, "Suspend, wowl config.\n");
55  
56 -       brcmf_configure_arp_offload(ifp, false);
57 +       brcmf_configure_arp_nd_offload(ifp, false);
58         brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->wowl.pre_pmmode);
59         brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
60  
61 @@ -4336,7 +4345,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
62  
63         if (!mbss) {
64                 brcmf_set_mpc(ifp, 0);
65 -               brcmf_configure_arp_offload(ifp, false);
66 +               brcmf_configure_arp_nd_offload(ifp, false);
67         }
68  
69         /* find the RSN_IE */
70 @@ -4482,7 +4491,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wi
71  exit:
72         if ((err) && (!mbss)) {
73                 brcmf_set_mpc(ifp, 1);
74 -               brcmf_configure_arp_offload(ifp, true);
75 +               brcmf_configure_arp_nd_offload(ifp, true);
76         }
77         return err;
78  }
79 @@ -4540,7 +4549,7 @@ static int brcmf_cfg80211_stop_ap(struct
80                         brcmf_err("bss_enable config failed %d\n", err);
81         }
82         brcmf_set_mpc(ifp, 1);
83 -       brcmf_configure_arp_offload(ifp, true);
84 +       brcmf_configure_arp_nd_offload(ifp, true);
85         clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
86         brcmf_net_setcarrier(ifp, false);
87  
88 @@ -6287,7 +6296,7 @@ static s32 brcmf_config_dongle(struct br
89         if (err)
90                 goto default_conf_out;
91  
92 -       brcmf_configure_arp_offload(ifp, true);
93 +       brcmf_configure_arp_nd_offload(ifp, true);
94  
95         cfg->dongle_up = true;
96  default_conf_out:
97 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
98 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
99 @@ -20,6 +20,8 @@
100  #include <linux/inetdevice.h>
101  #include <net/cfg80211.h>
102  #include <net/rtnetlink.h>
103 +#include <net/addrconf.h>
104 +#include <net/ipv6.h>
105  #include <brcmu_utils.h>
106  #include <brcmu_wifi.h>
107  
108 @@ -172,6 +174,35 @@ _brcmf_set_mac_address(struct work_struc
109         }
110  }
111  
112 +#if IS_ENABLED(CONFIG_IPV6)
113 +static void _brcmf_update_ndtable(struct work_struct *work)
114 +{
115 +       struct brcmf_if *ifp;
116 +       int i, ret;
117 +
118 +       ifp = container_of(work, struct brcmf_if, ndoffload_work);
119 +
120 +       /* clear the table in firmware */
121 +       ret = brcmf_fil_iovar_data_set(ifp, "nd_hostip_clear", NULL, 0);
122 +       if (ret) {
123 +               brcmf_dbg(TRACE, "fail to clear nd ip table err:%d\n", ret);
124 +               return;
125 +       }
126 +
127 +       for (i = 0; i < ifp->ipv6addr_idx; i++) {
128 +               ret = brcmf_fil_iovar_data_set(ifp, "nd_hostip",
129 +                                              &ifp->ipv6_addr_tbl[i],
130 +                                              sizeof(struct in6_addr));
131 +               if (ret)
132 +                       brcmf_err("add nd ip err %d\n", ret);
133 +       }
134 +}
135 +#else
136 +static void _brcmf_update_ndtable(struct work_struct *work)
137 +{
138 +}
139 +#endif
140 +
141  static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr)
142  {
143         struct brcmf_if *ifp = netdev_priv(ndev);
144 @@ -685,6 +716,7 @@ int brcmf_net_attach(struct brcmf_if *if
145  
146         INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address);
147         INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list);
148 +       INIT_WORK(&ifp->ndoffload_work, _brcmf_update_ndtable);
149  
150         if (rtnl_locked)
151                 err = register_netdevice(ndev);
152 @@ -884,6 +916,7 @@ static void brcmf_del_if(struct brcmf_pu
153                 if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
154                         cancel_work_sync(&ifp->setmacaddr_work);
155                         cancel_work_sync(&ifp->multicast_work);
156 +                       cancel_work_sync(&ifp->ndoffload_work);
157                 }
158                 brcmf_net_detach(ifp->ndev);
159         } else {
160 @@ -1025,6 +1058,56 @@ static int brcmf_inetaddr_changed(struct
161  }
162  #endif
163  
164 +#if IS_ENABLED(CONFIG_IPV6)
165 +static int brcmf_inet6addr_changed(struct notifier_block *nb,
166 +                                  unsigned long action, void *data)
167 +{
168 +       struct brcmf_pub *drvr = container_of(nb, struct brcmf_pub,
169 +                                             inet6addr_notifier);
170 +       struct inet6_ifaddr *ifa = data;
171 +       struct brcmf_if *ifp;
172 +       int i;
173 +       struct in6_addr *table;
174 +
175 +       /* Only handle primary interface */
176 +       ifp = drvr->iflist[0];
177 +       if (!ifp)
178 +               return NOTIFY_DONE;
179 +       if (ifp->ndev != ifa->idev->dev)
180 +               return NOTIFY_DONE;
181 +
182 +       table = ifp->ipv6_addr_tbl;
183 +       for (i = 0; i < NDOL_MAX_ENTRIES; i++)
184 +               if (ipv6_addr_equal(&ifa->addr, &table[i]))
185 +                       break;
186 +
187 +       switch (action) {
188 +       case NETDEV_UP:
189 +               if (i == NDOL_MAX_ENTRIES) {
190 +                       if (ifp->ipv6addr_idx < NDOL_MAX_ENTRIES) {
191 +                               table[ifp->ipv6addr_idx++] = ifa->addr;
192 +                       } else {
193 +                               for (i = 0; i < NDOL_MAX_ENTRIES - 1; i++)
194 +                                       table[i] = table[i + 1];
195 +                               table[NDOL_MAX_ENTRIES - 1] = ifa->addr;
196 +                       }
197 +               }
198 +               break;
199 +       case NETDEV_DOWN:
200 +               if (i < NDOL_MAX_ENTRIES)
201 +                       for (; i < ifp->ipv6addr_idx; i++)
202 +                               table[i] = table[i + 1];
203 +               break;
204 +       default:
205 +               break;
206 +       }
207 +
208 +       schedule_work(&ifp->ndoffload_work);
209 +
210 +       return NOTIFY_OK;
211 +}
212 +#endif
213 +
214  int brcmf_attach(struct device *dev)
215  {
216         struct brcmf_pub *drvr = NULL;
217 @@ -1164,30 +1247,41 @@ int brcmf_bus_start(struct device *dev)
218  #ifdef CONFIG_INET
219         drvr->inetaddr_notifier.notifier_call = brcmf_inetaddr_changed;
220         ret = register_inetaddr_notifier(&drvr->inetaddr_notifier);
221 +       if (ret)
222 +               goto fail;
223 +
224 +#if IS_ENABLED(CONFIG_IPV6)
225 +       drvr->inet6addr_notifier.notifier_call = brcmf_inet6addr_changed;
226 +       ret = register_inet6addr_notifier(&drvr->inet6addr_notifier);
227 +       if (ret) {
228 +               unregister_inetaddr_notifier(&drvr->inetaddr_notifier);
229 +               goto fail;
230 +       }
231  #endif
232 +#endif /* CONFIG_INET */
233 +
234 +       return 0;
235  
236  fail:
237 -       if (ret < 0) {
238 -               brcmf_err("failed: %d\n", ret);
239 -               if (drvr->config) {
240 -                       brcmf_cfg80211_detach(drvr->config);
241 -                       drvr->config = NULL;
242 -               }
243 -               if (drvr->fws) {
244 -                       brcmf_fws_del_interface(ifp);
245 -                       brcmf_fws_deinit(drvr);
246 -               }
247 -               if (ifp)
248 -                       brcmf_net_detach(ifp->ndev);
249 -               if (p2p_ifp)
250 -                       brcmf_net_detach(p2p_ifp->ndev);
251 -               drvr->iflist[0] = NULL;
252 -               drvr->iflist[1] = NULL;
253 -               if (brcmf_ignoring_probe_fail(drvr))
254 -                       ret = 0;
255 -               return ret;
256 +       brcmf_err("failed: %d\n", ret);
257 +       if (drvr->config) {
258 +               brcmf_cfg80211_detach(drvr->config);
259 +               drvr->config = NULL;
260 +       }
261 +       if (drvr->fws) {
262 +               brcmf_fws_del_interface(ifp);
263 +               brcmf_fws_deinit(drvr);
264         }
265 -       return 0;
266 +       if (ifp)
267 +               brcmf_net_detach(ifp->ndev);
268 +       if (p2p_ifp)
269 +               brcmf_net_detach(p2p_ifp->ndev);
270 +       drvr->iflist[0] = NULL;
271 +       drvr->iflist[1] = NULL;
272 +       if (brcmf_ignoring_probe_fail(drvr))
273 +               ret = 0;
274 +
275 +       return ret;
276  }
277  
278  void brcmf_bus_add_txhdrlen(struct device *dev, uint len)
279 @@ -1237,6 +1331,10 @@ void brcmf_detach(struct device *dev)
280         unregister_inetaddr_notifier(&drvr->inetaddr_notifier);
281  #endif
282  
283 +#if IS_ENABLED(CONFIG_IPV6)
284 +       unregister_inet6addr_notifier(&drvr->inet6addr_notifier);
285 +#endif
286 +
287         /* stop firmware event handling */
288         brcmf_fweh_detach(drvr);
289         if (drvr->config)
290 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
291 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
292 @@ -48,6 +48,8 @@
293   */
294  #define BRCMF_DRIVER_FIRMWARE_VERSION_LEN      32
295  
296 +#define NDOL_MAX_ENTRIES       8
297 +
298  /**
299   * struct brcmf_ampdu_rx_reorder - AMPDU receive reorder info
300   *
301 @@ -143,6 +145,7 @@ struct brcmf_pub {
302  #endif
303  
304         struct notifier_block inetaddr_notifier;
305 +       struct notifier_block inet6addr_notifier;
306         struct brcmf_mp_device *settings;
307  };
308  
309 @@ -175,6 +178,7 @@ enum brcmf_netif_stop_reason {
310   * @stats: interface specific network statistics.
311   * @setmacaddr_work: worker object for setting mac address.
312   * @multicast_work: worker object for multicast provisioning.
313 + * @ndoffload_work: worker object for neighbor discovery offload configuration.
314   * @fws_desc: interface specific firmware-signalling descriptor.
315   * @ifidx: interface index in device firmware.
316   * @bsscfgidx: index of bss associated with this interface.
317 @@ -191,6 +195,7 @@ struct brcmf_if {
318         struct net_device_stats stats;
319         struct work_struct setmacaddr_work;
320         struct work_struct multicast_work;
321 +       struct work_struct ndoffload_work;
322         struct brcmf_fws_mac_descriptor *fws_desc;
323         int ifidx;
324         s32 bsscfgidx;
325 @@ -199,6 +204,8 @@ struct brcmf_if {
326         spinlock_t netif_stop_lock;
327         atomic_t pend_8021x_cnt;
328         wait_queue_head_t pend_8021x_wait;
329 +       struct in6_addr ipv6_addr_tbl[NDOL_MAX_ENTRIES];
330 +       u8 ipv6addr_idx;
331  };
332  
333  struct brcmf_skb_reorder_data {