344-0006-brcmfmac-add-neighbor-discovery-offload-ip-address-t.patch 9.3 KB

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