wl_cfgp2p.c 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984
  1. /*
  2. * Linux cfgp2p driver
  3. *
  4. * Copyright (C) 1999-2011, Broadcom Corporation
  5. *
  6. * Unless you and Broadcom execute a separate written software license
  7. * agreement governing use of this software, this software is licensed to you
  8. * under the terms of the GNU General Public License version 2 (the "GPL"),
  9. * available at http://www.broadcom.com/licenses/GPLv2.php, with the
  10. * following added to such license:
  11. *
  12. * As a special exception, the copyright holders of this software give you
  13. * permission to link this software with independent modules, and to copy and
  14. * distribute the resulting executable under terms of your choice, provided that
  15. * you also meet, for each linked independent module, the terms and conditions of
  16. * the license of that module. An independent module is a module which is not
  17. * derived from this software. The special exception does not apply to any
  18. * modifications of the software.
  19. *
  20. * Notwithstanding the above, under no circumstances may you combine this
  21. * software in any way with any other Broadcom software provided under a license
  22. * other than the GPL, without Broadcom's express prior written consent.
  23. *
  24. * $Id: wl_cfgp2p.c,v 1.1.4.1.2.14 2011-02-09 01:40:07 $
  25. *
  26. */
  27. #include <typedefs.h>
  28. #include <linuxver.h>
  29. #include <osl.h>
  30. #include <linux/kernel.h>
  31. #include <linux/kthread.h>
  32. #include <linux/netdevice.h>
  33. #include <linux/etherdevice.h>
  34. #include <linux/types.h>
  35. #include <linux/string.h>
  36. #include <linux/timer.h>
  37. #include <linux/if_arp.h>
  38. #include <asm/uaccess.h>
  39. #include <bcmutils.h>
  40. #include <bcmendian.h>
  41. #include <proto/ethernet.h>
  42. #include <wl_cfg80211.h>
  43. #include <wl_cfgp2p.h>
  44. #include <wldev_common.h>
  45. #include <wl_android.h>
  46. static s8 scanparambuf[WLC_IOCTL_SMLEN];
  47. static bool
  48. wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type);
  49. static s32
  50. wl_cfgp2p_vndr_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, s32 pktflag,
  51. s8 *oui, s32 ie_id, s8 *data, s32 data_len, s32 delete);
  52. static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev);
  53. static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd);
  54. static int wl_cfgp2p_if_open(struct net_device *net);
  55. static int wl_cfgp2p_if_stop(struct net_device *net);
  56. static const struct net_device_ops wl_cfgp2p_if_ops = {
  57. .ndo_open = wl_cfgp2p_if_open,
  58. .ndo_stop = wl_cfgp2p_if_stop,
  59. .ndo_do_ioctl = wl_cfgp2p_do_ioctl,
  60. .ndo_start_xmit = wl_cfgp2p_start_xmit,
  61. };
  62. bool wl_cfgp2p_is_pub_action(void *frame, u32 frame_len)
  63. {
  64. wifi_p2p_pub_act_frame_t *pact_frm;
  65. if (frame == NULL)
  66. return false;
  67. pact_frm = (wifi_p2p_pub_act_frame_t *)frame;
  68. if (frame_len < sizeof(wifi_p2p_pub_act_frame_t) -1)
  69. return false;
  70. if (pact_frm->category == P2P_PUB_AF_CATEGORY &&
  71. pact_frm->action == P2P_PUB_AF_ACTION &&
  72. pact_frm->oui_type == P2P_VER &&
  73. memcmp(pact_frm->oui, P2P_OUI, sizeof(pact_frm->oui)) == 0) {
  74. return true;
  75. }
  76. return false;
  77. }
  78. bool wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len)
  79. {
  80. wifi_p2p_action_frame_t *act_frm;
  81. if (frame == NULL)
  82. return false;
  83. act_frm = (wifi_p2p_action_frame_t *)frame;
  84. if (frame_len < sizeof(wifi_p2p_action_frame_t) -1)
  85. return false;
  86. if (act_frm->category == P2P_AF_CATEGORY &&
  87. act_frm->type == P2P_VER &&
  88. memcmp(act_frm->OUI, P2P_OUI, DOT11_OUI_LEN) == 0) {
  89. return true;
  90. }
  91. return false;
  92. }
  93. bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len)
  94. {
  95. wifi_p2psd_gas_pub_act_frame_t *sd_act_frm;
  96. if (frame == NULL)
  97. return false;
  98. sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame;
  99. if (frame_len < sizeof(wifi_p2psd_gas_pub_act_frame_t) - 1)
  100. return false;
  101. if (sd_act_frm->category != P2PSD_ACTION_CATEGORY)
  102. return false;
  103. if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ ||
  104. sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP ||
  105. sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ ||
  106. sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP)
  107. return true;
  108. else
  109. return false;
  110. }
  111. void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len)
  112. {
  113. wifi_p2p_pub_act_frame_t *pact_frm;
  114. wifi_p2p_action_frame_t *act_frm;
  115. wifi_p2psd_gas_pub_act_frame_t *sd_act_frm;
  116. if (!frame || frame_len <= 2)
  117. return;
  118. if (wl_cfgp2p_is_pub_action(frame, frame_len)) {
  119. pact_frm = (wifi_p2p_pub_act_frame_t *)frame;
  120. switch (pact_frm->subtype) {
  121. case P2P_PAF_GON_REQ:
  122. CFGP2P_DBG(("%s P2P Group Owner Negotiation Req Frame\n",
  123. (tx)? "TX": "RX"));
  124. break;
  125. case P2P_PAF_GON_RSP:
  126. CFGP2P_DBG(("%s P2P Group Owner Negotiation Rsp Frame\n",
  127. (tx)? "TX": "RX"));
  128. break;
  129. case P2P_PAF_GON_CONF:
  130. CFGP2P_DBG(("%s P2P Group Owner Negotiation Confirm Frame\n",
  131. (tx)? "TX": "RX"));
  132. break;
  133. case P2P_PAF_INVITE_REQ:
  134. CFGP2P_DBG(("%s P2P Invitation Request Frame\n",
  135. (tx)? "TX": "RX"));
  136. break;
  137. case P2P_PAF_INVITE_RSP:
  138. CFGP2P_DBG(("%s P2P Invitation Response Frame\n",
  139. (tx)? "TX": "RX"));
  140. break;
  141. case P2P_PAF_DEVDIS_REQ:
  142. CFGP2P_DBG(("%s P2P Device Discoverability Request Frame\n",
  143. (tx)? "TX": "RX"));
  144. break;
  145. case P2P_PAF_DEVDIS_RSP:
  146. CFGP2P_DBG(("%s P2P Device Discoverability Response Frame\n",
  147. (tx)? "TX": "RX"));
  148. break;
  149. case P2P_PAF_PROVDIS_REQ:
  150. CFGP2P_DBG(("%s P2P Provision Discovery Request Frame\n",
  151. (tx)? "TX": "RX"));
  152. break;
  153. case P2P_PAF_PROVDIS_RSP:
  154. CFGP2P_DBG(("%s P2P Provision Discovery Response Frame\n",
  155. (tx)? "TX": "RX"));
  156. break;
  157. default:
  158. CFGP2P_DBG(("%s Unknown P2P Public Action Frame\n",
  159. (tx)? "TX": "RX"));
  160. }
  161. } else if (wl_cfgp2p_is_p2p_action(frame, frame_len)) {
  162. act_frm = (wifi_p2p_action_frame_t *)frame;
  163. switch (act_frm->subtype) {
  164. case P2P_AF_NOTICE_OF_ABSENCE:
  165. CFGP2P_DBG(("%s P2P Notice of Absence Frame\n",
  166. (tx)? "TX": "RX"));
  167. break;
  168. case P2P_AF_PRESENCE_REQ:
  169. CFGP2P_DBG(("%s P2P Presence Request Frame\n",
  170. (tx)? "TX": "RX"));
  171. break;
  172. case P2P_AF_PRESENCE_RSP:
  173. CFGP2P_DBG(("%s P2P Presence Response Frame\n",
  174. (tx)? "TX": "RX"));
  175. break;
  176. case P2P_AF_GO_DISC_REQ:
  177. CFGP2P_DBG(("%s P2P Discoverability Request Frame\n",
  178. (tx)? "TX": "RX"));
  179. break;
  180. default:
  181. CFGP2P_DBG(("%s Unknown P2P Action Frame\n",
  182. (tx)? "TX": "RX"));
  183. }
  184. } else if (wl_cfgp2p_is_gas_action(frame, frame_len)) {
  185. sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame;
  186. switch (sd_act_frm->action) {
  187. case P2PSD_ACTION_ID_GAS_IREQ:
  188. CFGP2P_DBG(("%s P2P GAS Initial Request\n",
  189. (tx)? "TX" : "RX"));
  190. break;
  191. case P2PSD_ACTION_ID_GAS_IRESP:
  192. CFGP2P_DBG(("%s P2P GAS Initial Response\n",
  193. (tx)? "TX" : "RX"));
  194. break;
  195. case P2PSD_ACTION_ID_GAS_CREQ:
  196. CFGP2P_DBG(("%s P2P GAS Comback Request\n",
  197. (tx)? "TX" : "RX"));
  198. break;
  199. case P2PSD_ACTION_ID_GAS_CRESP:
  200. CFGP2P_DBG(("%s P2P GAS Comback Response\n",
  201. (tx)? "TX" : "RX"));
  202. break;
  203. default:
  204. CFGP2P_DBG(("%s Unknown P2P GAS Frame\n",
  205. (tx)? "TX" : "RX"));
  206. }
  207. }
  208. }
  209. /*
  210. * Initialize variables related to P2P
  211. *
  212. */
  213. s32
  214. wl_cfgp2p_init_priv(struct wl_priv *wl)
  215. {
  216. if (!(wl->p2p = kzalloc(sizeof(struct p2p_info), GFP_KERNEL))) {
  217. CFGP2P_ERR(("struct p2p_info allocation failed\n"));
  218. return -ENOMEM;
  219. }
  220. #define INIT_IE(IE_TYPE, BSS_TYPE) \
  221. do { \
  222. memset(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \
  223. sizeof(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \
  224. wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \
  225. } while (0);
  226. INIT_IE(probe_req, P2PAPI_BSSCFG_PRIMARY);
  227. INIT_IE(probe_res, P2PAPI_BSSCFG_PRIMARY);
  228. INIT_IE(assoc_req, P2PAPI_BSSCFG_PRIMARY);
  229. INIT_IE(assoc_res, P2PAPI_BSSCFG_PRIMARY);
  230. INIT_IE(beacon, P2PAPI_BSSCFG_PRIMARY);
  231. INIT_IE(probe_req, P2PAPI_BSSCFG_DEVICE);
  232. INIT_IE(probe_res, P2PAPI_BSSCFG_DEVICE);
  233. INIT_IE(assoc_req, P2PAPI_BSSCFG_DEVICE);
  234. INIT_IE(assoc_res, P2PAPI_BSSCFG_DEVICE);
  235. INIT_IE(beacon, P2PAPI_BSSCFG_DEVICE);
  236. INIT_IE(probe_req, P2PAPI_BSSCFG_CONNECTION);
  237. INIT_IE(probe_res, P2PAPI_BSSCFG_CONNECTION);
  238. INIT_IE(assoc_req, P2PAPI_BSSCFG_CONNECTION);
  239. INIT_IE(assoc_res, P2PAPI_BSSCFG_CONNECTION);
  240. INIT_IE(beacon, P2PAPI_BSSCFG_CONNECTION);
  241. #undef INIT_IE
  242. wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY) = wl_to_prmry_ndev(wl);
  243. wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY) = 0;
  244. wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = NULL;
  245. wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = 0;
  246. wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION) = NULL;
  247. wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) = 0;
  248. return BCME_OK;
  249. }
  250. /*
  251. * Deinitialize variables related to P2P
  252. *
  253. */
  254. void
  255. wl_cfgp2p_deinit_priv(struct wl_priv *wl)
  256. {
  257. CFGP2P_DBG(("In\n"));
  258. if (wl->p2p) {
  259. kfree(wl->p2p);
  260. wl->p2p = NULL;
  261. }
  262. wl->p2p_supported = 0;
  263. }
  264. /*
  265. * Set P2P functions into firmware
  266. */
  267. s32
  268. wl_cfgp2p_set_firm_p2p(struct wl_priv *wl)
  269. {
  270. struct net_device *ndev = wl_to_prmry_ndev(wl);
  271. struct ether_addr null_eth_addr = { { 0, 0, 0, 0, 0, 0 } };
  272. s32 ret = BCME_OK;
  273. s32 val = 0;
  274. /* Do we have to check whether APSTA is enabled or not ? */
  275. wldev_iovar_getint(ndev, "apsta", &val);
  276. if (val == 0) {
  277. val = 1;
  278. wldev_ioctl(ndev, WLC_DOWN, &val, sizeof(s32), true);
  279. wldev_iovar_setint(ndev, "apsta", val);
  280. wldev_ioctl(ndev, WLC_UP, &val, sizeof(s32), true);
  281. }
  282. val = 1;
  283. /* Disable firmware roaming for P2P */
  284. wldev_iovar_setint(ndev, "roam_off", val);
  285. /* In case of COB type, firmware has default mac address
  286. * After Initializing firmware, we have to set current mac address to
  287. * firmware for P2P device address
  288. */
  289. ret = wldev_iovar_setbuf_bsscfg(ndev, "p2p_da_override", &null_eth_addr,
  290. sizeof(null_eth_addr), wl->ioctl_buf, WLC_IOCTL_MAXLEN, 0, &wl->ioctl_buf_sync);
  291. if (ret && ret != BCME_UNSUPPORTED) {
  292. CFGP2P_ERR(("failed to update device address ret %d\n", ret));
  293. }
  294. return ret;
  295. }
  296. /* Create a new P2P BSS.
  297. * Parameters:
  298. * @mac : MAC address of the BSS to create
  299. * @if_type : interface type: WL_P2P_IF_GO or WL_P2P_IF_CLIENT
  300. * @chspec : chspec to use if creating a GO BSS.
  301. * Returns 0 if success.
  302. */
  303. s32
  304. wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type,
  305. chanspec_t chspec)
  306. {
  307. wl_p2p_if_t ifreq;
  308. s32 err;
  309. struct net_device *ndev = wl_to_prmry_ndev(wl);
  310. ifreq.type = if_type;
  311. ifreq.chspec = chspec;
  312. memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet));
  313. CFGP2P_DBG(("---wl p2p_ifadd %02x:%02x:%02x:%02x:%02x:%02x %s %u\n",
  314. ifreq.addr.octet[0], ifreq.addr.octet[1], ifreq.addr.octet[2],
  315. ifreq.addr.octet[3], ifreq.addr.octet[4], ifreq.addr.octet[5],
  316. (if_type == WL_P2P_IF_GO) ? "go" : "client",
  317. (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT));
  318. err = wldev_iovar_setbuf(ndev, "p2p_ifadd", &ifreq, sizeof(ifreq),
  319. wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
  320. return err;
  321. }
  322. /* Delete a P2P BSS.
  323. * Parameters:
  324. * @mac : MAC address of the BSS to create
  325. * Returns 0 if success.
  326. */
  327. s32
  328. wl_cfgp2p_ifdel(struct wl_priv *wl, struct ether_addr *mac)
  329. {
  330. s32 ret;
  331. struct net_device *netdev = wl_to_prmry_ndev(wl);
  332. CFGP2P_INFO(("------primary idx %d : wl p2p_ifdel %02x:%02x:%02x:%02x:%02x:%02x\n",
  333. netdev->ifindex, mac->octet[0], mac->octet[1], mac->octet[2],
  334. mac->octet[3], mac->octet[4], mac->octet[5]));
  335. ret = wldev_iovar_setbuf(netdev, "p2p_ifdel", mac, sizeof(*mac),
  336. wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
  337. if (unlikely(ret < 0)) {
  338. printk("'wl p2p_ifdel' error %d\n", ret);
  339. }
  340. return ret;
  341. }
  342. /* Change a P2P Role.
  343. * Parameters:
  344. * @mac : MAC address of the BSS to change a role
  345. * Returns 0 if success.
  346. */
  347. s32
  348. wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type,
  349. chanspec_t chspec)
  350. {
  351. wl_p2p_if_t ifreq;
  352. s32 err;
  353. struct net_device *netdev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION);
  354. ifreq.type = if_type;
  355. ifreq.chspec = chspec;
  356. memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet));
  357. CFGP2P_INFO(("---wl p2p_ifchange %02x:%02x:%02x:%02x:%02x:%02x %s %u\n",
  358. ifreq.addr.octet[0], ifreq.addr.octet[1], ifreq.addr.octet[2],
  359. ifreq.addr.octet[3], ifreq.addr.octet[4], ifreq.addr.octet[5],
  360. (if_type == WL_P2P_IF_GO) ? "go" : "client",
  361. (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT));
  362. err = wldev_iovar_setbuf(netdev, "p2p_ifupd", &ifreq, sizeof(ifreq),
  363. wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
  364. if (unlikely(err < 0)) {
  365. printk("'wl p2p_ifupd' error %d\n", err);
  366. }
  367. return err;
  368. }
  369. /* Get the index of a created P2P BSS.
  370. * Parameters:
  371. * @mac : MAC address of the created BSS
  372. * @index : output: index of created BSS
  373. * Returns 0 if success.
  374. */
  375. s32
  376. wl_cfgp2p_ifidx(struct wl_priv *wl, struct ether_addr *mac, s32 *index)
  377. {
  378. s32 ret;
  379. u8 getbuf[64];
  380. struct net_device *dev = wl_to_prmry_ndev(wl);
  381. CFGP2P_INFO(("---wl p2p_if %02x:%02x:%02x:%02x:%02x:%02x\n",
  382. mac->octet[0], mac->octet[1], mac->octet[2],
  383. mac->octet[3], mac->octet[4], mac->octet[5]));
  384. ret = wldev_iovar_getbuf_bsscfg(dev, "p2p_if", mac, sizeof(*mac), getbuf,
  385. sizeof(getbuf), wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY), NULL);
  386. if (ret == 0) {
  387. memcpy(index, getbuf, sizeof(index));
  388. CFGP2P_INFO(("---wl p2p_if ==> %d\n", *index));
  389. }
  390. return ret;
  391. }
  392. static s32
  393. wl_cfgp2p_set_discovery(struct wl_priv *wl, s32 on)
  394. {
  395. s32 ret = BCME_OK;
  396. struct net_device *ndev = wl_to_prmry_ndev(wl);
  397. CFGP2P_DBG(("enter\n"));
  398. ret = wldev_iovar_setint(ndev, "p2p_disc", on);
  399. if (unlikely(ret < 0)) {
  400. CFGP2P_ERR(("p2p_disc %d error %d\n", on, ret));
  401. }
  402. return ret;
  403. }
  404. /* Set the WL driver's P2P mode.
  405. * Parameters :
  406. * @mode : is one of WL_P2P_DISC_ST_{SCAN,LISTEN,SEARCH}.
  407. * @channel : the channel to listen
  408. * @listen_ms : the time (milli seconds) to wait
  409. * @bssidx : bss index for BSSCFG
  410. * Returns 0 if success
  411. */
  412. s32
  413. wl_cfgp2p_set_p2p_mode(struct wl_priv *wl, u8 mode, u32 channel, u16 listen_ms, int bssidx)
  414. {
  415. wl_p2p_disc_st_t discovery_mode;
  416. s32 ret;
  417. struct net_device *dev;
  418. CFGP2P_DBG(("enter\n"));
  419. if (unlikely(bssidx >= P2PAPI_BSSCFG_MAX)) {
  420. CFGP2P_ERR((" %d index out of range\n", bssidx));
  421. return -1;
  422. }
  423. dev = wl_to_p2p_bss_ndev(wl, bssidx);
  424. if (unlikely(dev == NULL)) {
  425. CFGP2P_ERR(("bssidx %d is not assigned\n", bssidx));
  426. return BCME_NOTFOUND;
  427. }
  428. /* Put the WL driver into P2P Listen Mode to respond to P2P probe reqs */
  429. discovery_mode.state = mode;
  430. discovery_mode.chspec = CH20MHZ_CHSPEC(channel);
  431. discovery_mode.dwell = listen_ms;
  432. ret = wldev_iovar_setbuf_bsscfg(dev, "p2p_state", &discovery_mode,
  433. sizeof(discovery_mode), wl->ioctl_buf, WLC_IOCTL_MAXLEN,
  434. bssidx, &wl->ioctl_buf_sync);
  435. return ret;
  436. }
  437. /* Get the index of the P2P Discovery BSS */
  438. static s32
  439. wl_cfgp2p_get_disc_idx(struct wl_priv *wl, s32 *index)
  440. {
  441. s32 ret;
  442. struct net_device *dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY);
  443. ret = wldev_iovar_getint(dev, "p2p_dev", index);
  444. CFGP2P_INFO(("p2p_dev bsscfg_idx=%d ret=%d\n", *index, ret));
  445. if (unlikely(ret < 0)) {
  446. CFGP2P_ERR(("'p2p_dev' error %d\n", ret));
  447. return ret;
  448. }
  449. return ret;
  450. }
  451. s32
  452. wl_cfgp2p_init_discovery(struct wl_priv *wl)
  453. {
  454. s32 index = 0;
  455. s32 ret = BCME_OK;
  456. CFGP2P_DBG(("enter\n"));
  457. if (wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) != 0) {
  458. CFGP2P_ERR(("do nothing, already initialized\n"));
  459. return ret;
  460. }
  461. ret = wl_cfgp2p_set_discovery(wl, 1);
  462. if (ret < 0) {
  463. CFGP2P_ERR(("set discover error\n"));
  464. return ret;
  465. }
  466. /* Enable P2P Discovery in the WL Driver */
  467. ret = wl_cfgp2p_get_disc_idx(wl, &index);
  468. if (ret < 0) {
  469. return ret;
  470. }
  471. wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) =
  472. wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY);
  473. wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = index;
  474. /* Set the initial discovery state to SCAN */
  475. ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0,
  476. wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
  477. if (unlikely(ret != 0)) {
  478. CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n"));
  479. wl_cfgp2p_set_discovery(wl, 0);
  480. wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = 0;
  481. wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = NULL;
  482. return 0;
  483. }
  484. return ret;
  485. }
  486. /* Deinitialize P2P Discovery
  487. * Parameters :
  488. * @wl : wl_private data
  489. * Returns 0 if succes
  490. */
  491. static s32
  492. wl_cfgp2p_deinit_discovery(struct wl_priv *wl)
  493. {
  494. s32 ret = BCME_OK;
  495. CFGP2P_DBG(("enter\n"));
  496. if (wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) == 0) {
  497. CFGP2P_ERR(("do nothing, not initialized\n"));
  498. return -1;
  499. }
  500. /* Set the discovery state to SCAN */
  501. ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0,
  502. wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
  503. /* Disable P2P discovery in the WL driver (deletes the discovery BSSCFG) */
  504. ret = wl_cfgp2p_set_discovery(wl, 0);
  505. /* Clear our saved WPS and P2P IEs for the discovery BSS. The driver
  506. * deleted these IEs when wl_cfgp2p_set_discovery() deleted the discovery
  507. * BSS.
  508. */
  509. /* Clear the saved bsscfg index of the discovery BSSCFG to indicate we
  510. * have no discovery BSS.
  511. */
  512. wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = 0;
  513. wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = NULL;
  514. return ret;
  515. }
  516. /* Enable P2P Discovery
  517. * Parameters:
  518. * @wl : wl_private data
  519. * @ie : probe request ie (WPS IE + P2P IE)
  520. * @ie_len : probe request ie length
  521. * Returns 0 if success.
  522. */
  523. s32
  524. wl_cfgp2p_enable_discovery(struct wl_priv *wl, struct net_device *dev,
  525. const u8 *ie, u32 ie_len)
  526. {
  527. s32 ret = BCME_OK;
  528. if (wl_get_p2p_status(wl, DISCOVERY_ON)) {
  529. CFGP2P_INFO((" DISCOVERY is already initialized, we have nothing to do\n"));
  530. goto set_ie;
  531. }
  532. wl_set_p2p_status(wl, DISCOVERY_ON);
  533. CFGP2P_DBG(("enter\n"));
  534. ret = wl_cfgp2p_init_discovery(wl);
  535. if (unlikely(ret < 0)) {
  536. CFGP2P_ERR((" init discovery error %d\n", ret));
  537. goto exit;
  538. }
  539. /* Set wsec to any non-zero value in the discovery bsscfg to ensure our
  540. * P2P probe responses have the privacy bit set in the 802.11 WPA IE.
  541. * Some peer devices may not initiate WPS with us if this bit is not set.
  542. */
  543. ret = wldev_iovar_setint_bsscfg(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE),
  544. "wsec", AES_ENABLED, wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
  545. if (unlikely(ret < 0)) {
  546. CFGP2P_ERR((" wsec error %d\n", ret));
  547. }
  548. set_ie:
  549. ret = wl_cfgp2p_set_management_ie(wl, dev,
  550. wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE),
  551. VNDR_IE_PRBREQ_FLAG, ie, ie_len);
  552. if (unlikely(ret < 0)) {
  553. CFGP2P_ERR(("set probreq ie occurs error %d\n", ret));
  554. goto exit;
  555. }
  556. exit:
  557. return ret;
  558. }
  559. /* Disable P2P Discovery
  560. * Parameters:
  561. * @wl : wl_private_data
  562. * Returns 0 if success.
  563. */
  564. s32
  565. wl_cfgp2p_disable_discovery(struct wl_priv *wl)
  566. {
  567. s32 ret = BCME_OK;
  568. CFGP2P_DBG((" enter\n"));
  569. wl_clr_p2p_status(wl, DISCOVERY_ON);
  570. if (wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) == 0) {
  571. CFGP2P_ERR((" do nothing, not initialized\n"));
  572. goto exit;
  573. }
  574. ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0,
  575. wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
  576. if (unlikely(ret < 0)) {
  577. CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n"));
  578. }
  579. /* Do a scan abort to stop the driver's scan engine in case it is still
  580. * waiting out an action frame tx dwell time.
  581. */
  582. #ifdef NOT_YET
  583. if (wl_get_p2p_status(wl, SCANNING)) {
  584. p2pwlu_scan_abort(hdl, FALSE);
  585. }
  586. #endif
  587. wl_clr_p2p_status(wl, DISCOVERY_ON);
  588. ret = wl_cfgp2p_deinit_discovery(wl);
  589. exit:
  590. return ret;
  591. }
  592. s32
  593. wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active,
  594. u32 num_chans, u16 *channels,
  595. s32 search_state, u16 action, u32 bssidx)
  596. {
  597. s32 ret = BCME_OK;
  598. s32 memsize;
  599. s32 eparams_size;
  600. u32 i;
  601. s8 *memblk;
  602. wl_p2p_scan_t *p2p_params;
  603. wl_escan_params_t *eparams;
  604. wlc_ssid_t ssid;
  605. /* Scan parameters */
  606. #define P2PAPI_SCAN_NPROBES 1
  607. #define P2PAPI_SCAN_DWELL_TIME_MS 50
  608. #define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 40
  609. #define P2PAPI_SCAN_HOME_TIME_MS 60
  610. struct net_device *pri_dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY);
  611. wl_set_p2p_status(wl, SCANNING);
  612. /* Allocate scan params which need space for 3 channels and 0 ssids */
  613. eparams_size = (WL_SCAN_PARAMS_FIXED_SIZE +
  614. OFFSETOF(wl_escan_params_t, params)) +
  615. num_chans * sizeof(eparams->params.channel_list[0]);
  616. memsize = sizeof(wl_p2p_scan_t) + eparams_size;
  617. memblk = scanparambuf;
  618. if (memsize > sizeof(scanparambuf)) {
  619. CFGP2P_ERR((" scanpar buf too small (%u > %u)\n",
  620. memsize, sizeof(scanparambuf)));
  621. return -1;
  622. }
  623. memset(memblk, 0, memsize);
  624. memset(wl->ioctl_buf, 0, WLC_IOCTL_MAXLEN);
  625. if (search_state == WL_P2P_DISC_ST_SEARCH) {
  626. /*
  627. * If we in SEARCH STATE, we don't need to set SSID explictly
  628. * because dongle use P2P WILDCARD internally by default
  629. */
  630. wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SEARCH, 0, 0, bssidx);
  631. ssid.SSID_len = htod32(0);
  632. } else if (search_state == WL_P2P_DISC_ST_SCAN) {
  633. /* SCAN STATE 802.11 SCAN
  634. * WFD Supplicant has p2p_find command with (type=progressive, type= full)
  635. * So if P2P_find command with type=progressive,
  636. * we have to set ssid to P2P WILDCARD because
  637. * we just do broadcast scan unless setting SSID
  638. */
  639. strcpy(ssid.SSID, WL_P2P_WILDCARD_SSID);
  640. ssid.SSID_len = htod32(WL_P2P_WILDCARD_SSID_LEN);
  641. wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, bssidx);
  642. }
  643. /* Fill in the P2P scan structure at the start of the iovar param block */
  644. p2p_params = (wl_p2p_scan_t*) memblk;
  645. p2p_params->type = 'E';
  646. /* Fill in the Scan structure that follows the P2P scan structure */
  647. eparams = (wl_escan_params_t*) (p2p_params + 1);
  648. eparams->params.bss_type = DOT11_BSSTYPE_ANY;
  649. if (active)
  650. eparams->params.scan_type = DOT11_SCANTYPE_ACTIVE;
  651. else
  652. eparams->params.scan_type = DOT11_SCANTYPE_PASSIVE;
  653. memcpy(&eparams->params.bssid, &ether_bcast, ETHER_ADDR_LEN);
  654. if (ssid.SSID_len)
  655. memcpy(&eparams->params.ssid, &ssid, sizeof(wlc_ssid_t));
  656. eparams->params.nprobes = htod32(P2PAPI_SCAN_NPROBES);
  657. eparams->params.home_time = htod32(P2PAPI_SCAN_HOME_TIME_MS);
  658. if (wl_get_drv_status_all(wl, CONNECTED))
  659. eparams->params.active_time = htod32(-1);
  660. else if (num_chans == 3)
  661. eparams->params.active_time = htod32(P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS);
  662. else
  663. eparams->params.active_time = htod32(P2PAPI_SCAN_DWELL_TIME_MS);
  664. eparams->params.passive_time = htod32(-1);
  665. eparams->params.channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) |
  666. (num_chans & WL_SCAN_PARAMS_COUNT_MASK));
  667. for (i = 0; i < num_chans; i++) {
  668. eparams->params.channel_list[i] = htodchanspec(channels[i]);
  669. }
  670. eparams->version = htod32(ESCAN_REQ_VERSION);
  671. eparams->action = htod16(action);
  672. eparams->sync_id = htod16(0x1234);
  673. CFGP2P_INFO(("SCAN CHANNELS : "));
  674. for (i = 0; i < num_chans; i++) {
  675. if (i == 0) CFGP2P_INFO(("%d", channels[i]));
  676. else CFGP2P_INFO((",%d", channels[i]));
  677. }
  678. CFGP2P_INFO(("\n"));
  679. ret = wldev_iovar_setbuf_bsscfg(pri_dev, "p2p_scan",
  680. memblk, memsize, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
  681. return ret;
  682. }
  683. /* search function to reach at common channel to send action frame
  684. * Parameters:
  685. * @wl : wl_private data
  686. * @ndev : net device for bssidx
  687. * @bssidx : bssidx for BSS
  688. * Returns 0 if success.
  689. */
  690. s32
  691. wl_cfgp2p_act_frm_search(struct wl_priv *wl, struct net_device *ndev,
  692. s32 bssidx, s32 channel)
  693. {
  694. s32 ret = 0;
  695. u32 chan_cnt = 0;
  696. u16 *default_chan_list = NULL;
  697. if (!p2p_is_on(wl))
  698. return -BCME_ERROR;
  699. CFGP2P_ERR((" Enter\n"));
  700. if (bssidx == P2PAPI_BSSCFG_PRIMARY)
  701. bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
  702. if (channel)
  703. chan_cnt = 1;
  704. else
  705. chan_cnt = SOCIAL_CHAN_CNT;
  706. default_chan_list = kzalloc(chan_cnt * sizeof(*default_chan_list), GFP_KERNEL);
  707. if (default_chan_list == NULL) {
  708. CFGP2P_ERR(("channel list allocation failed \n"));
  709. ret = -ENOMEM;
  710. goto exit;
  711. }
  712. if (channel) {
  713. default_chan_list[0] = channel;
  714. } else {
  715. default_chan_list[0] = SOCIAL_CHAN_1;
  716. default_chan_list[1] = SOCIAL_CHAN_2;
  717. default_chan_list[2] = SOCIAL_CHAN_3;
  718. }
  719. ret = wl_cfgp2p_escan(wl, ndev, true, SOCIAL_CHAN_CNT,
  720. default_chan_list, WL_P2P_DISC_ST_SEARCH,
  721. WL_SCAN_ACTION_START, bssidx);
  722. kfree(default_chan_list);
  723. exit:
  724. return ret;
  725. }
  726. /* Check whether pointed-to IE looks like WPA. */
  727. #define wl_cfgp2p_is_wpa_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \
  728. (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPA_OUI_TYPE)
  729. /* Check whether pointed-to IE looks like WPS. */
  730. #define wl_cfgp2p_is_wps_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \
  731. (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPS_OUI_TYPE)
  732. /* Check whether the given IE looks like WFA P2P IE. */
  733. #define wl_cfgp2p_is_p2p_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \
  734. (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_P2P)
  735. /* Delete and Set a management vndr ie to firmware
  736. * Parameters:
  737. * @wl : wl_private data
  738. * @ndev : net device for bssidx
  739. * @bssidx : bssidx for BSS
  740. * @pktflag : packet flag for IE (VNDR_IE_PRBREQ_FLAG,VNDR_IE_PRBRSP_FLAG, VNDR_IE_ASSOCRSP_FLAG,
  741. * VNDR_IE_ASSOCREQ_FLAG)
  742. * @ie : VNDR IE (such as P2P IE , WPS IE)
  743. * @ie_len : VNDR IE Length
  744. * Returns 0 if success.
  745. */
  746. s32
  747. wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx,
  748. s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len)
  749. {
  750. /* Vendor-specific Information Element ID */
  751. #define VNDR_SPEC_ELEMENT_ID 0xdd
  752. s32 ret = BCME_OK;
  753. u32 pos;
  754. u8 *ie_buf;
  755. u8 *mgmt_ie_buf = NULL;
  756. u32 mgmt_ie_buf_len = 0;
  757. u32 *mgmt_ie_len = 0;
  758. u8 ie_id, ie_len;
  759. u8 delete = 0;
  760. #define IE_TYPE(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie)
  761. #define IE_TYPE_LEN(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie_len)
  762. if (p2p_is_on(wl) && bssidx != -1) {
  763. if (bssidx == P2PAPI_BSSCFG_PRIMARY)
  764. bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
  765. switch (pktflag) {
  766. case VNDR_IE_PRBREQ_FLAG :
  767. mgmt_ie_buf = IE_TYPE(probe_req, bssidx);
  768. mgmt_ie_len = &IE_TYPE_LEN(probe_req, bssidx);
  769. mgmt_ie_buf_len = sizeof(IE_TYPE(probe_req, bssidx));
  770. break;
  771. case VNDR_IE_PRBRSP_FLAG :
  772. mgmt_ie_buf = IE_TYPE(probe_res, bssidx);
  773. mgmt_ie_len = &IE_TYPE_LEN(probe_res, bssidx);
  774. mgmt_ie_buf_len = sizeof(IE_TYPE(probe_res, bssidx));
  775. break;
  776. case VNDR_IE_ASSOCREQ_FLAG :
  777. mgmt_ie_buf = IE_TYPE(assoc_req, bssidx);
  778. mgmt_ie_len = &IE_TYPE_LEN(assoc_req, bssidx);
  779. mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_req, bssidx));
  780. break;
  781. case VNDR_IE_ASSOCRSP_FLAG :
  782. mgmt_ie_buf = IE_TYPE(assoc_res, bssidx);
  783. mgmt_ie_len = &IE_TYPE_LEN(assoc_res, bssidx);
  784. mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_res, bssidx));
  785. break;
  786. case VNDR_IE_BEACON_FLAG :
  787. mgmt_ie_buf = IE_TYPE(beacon, bssidx);
  788. mgmt_ie_len = &IE_TYPE_LEN(beacon, bssidx);
  789. mgmt_ie_buf_len = sizeof(IE_TYPE(beacon, bssidx));
  790. break;
  791. default:
  792. mgmt_ie_buf = NULL;
  793. mgmt_ie_len = NULL;
  794. CFGP2P_ERR(("not suitable type\n"));
  795. return -1;
  796. }
  797. } else if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) {
  798. switch (pktflag) {
  799. case VNDR_IE_PRBRSP_FLAG :
  800. mgmt_ie_buf = wl->ap_info->probe_res_ie;
  801. mgmt_ie_len = &wl->ap_info->probe_res_ie_len;
  802. mgmt_ie_buf_len = sizeof(wl->ap_info->probe_res_ie);
  803. break;
  804. case VNDR_IE_BEACON_FLAG :
  805. mgmt_ie_buf = wl->ap_info->beacon_ie;
  806. mgmt_ie_len = &wl->ap_info->beacon_ie_len;
  807. mgmt_ie_buf_len = sizeof(wl->ap_info->beacon_ie);
  808. break;
  809. default:
  810. mgmt_ie_buf = NULL;
  811. mgmt_ie_len = NULL;
  812. CFGP2P_ERR(("not suitable type\n"));
  813. return -1;
  814. }
  815. bssidx = 0;
  816. } else if (bssidx == -1 && wl_get_mode_by_netdev(wl, ndev) == WL_MODE_BSS) {
  817. switch (pktflag) {
  818. case VNDR_IE_PRBREQ_FLAG :
  819. mgmt_ie_buf = wl->sta_info->probe_req_ie;
  820. mgmt_ie_len = &wl->sta_info->probe_req_ie_len;
  821. mgmt_ie_buf_len = sizeof(wl->sta_info->probe_req_ie);
  822. break;
  823. case VNDR_IE_ASSOCREQ_FLAG :
  824. mgmt_ie_buf = wl->sta_info->assoc_req_ie;
  825. mgmt_ie_len = &wl->sta_info->assoc_req_ie_len;
  826. mgmt_ie_buf_len = sizeof(wl->sta_info->assoc_req_ie);
  827. break;
  828. default:
  829. mgmt_ie_buf = NULL;
  830. mgmt_ie_len = NULL;
  831. CFGP2P_ERR(("not suitable type\n"));
  832. return -1;
  833. }
  834. bssidx = 0;
  835. } else {
  836. CFGP2P_ERR(("not suitable type\n"));
  837. return -1;
  838. }
  839. if (vndr_ie_len > mgmt_ie_buf_len) {
  840. CFGP2P_ERR(("extra IE size too big\n"));
  841. ret = -ENOMEM;
  842. } else {
  843. if (mgmt_ie_buf != NULL) {
  844. if (vndr_ie_len && (vndr_ie_len == *mgmt_ie_len) &&
  845. (memcmp(mgmt_ie_buf, vndr_ie, vndr_ie_len) == 0)) {
  846. CFGP2P_INFO(("Previous mgmt IE is equals to current IE"));
  847. goto exit;
  848. }
  849. pos = 0;
  850. delete = 1;
  851. ie_buf = (u8 *) mgmt_ie_buf;
  852. while (pos < *mgmt_ie_len) {
  853. ie_id = ie_buf[pos++];
  854. ie_len = ie_buf[pos++];
  855. if ((ie_id == DOT11_MNG_VS_ID) &&
  856. (wl_cfgp2p_is_wps_ie(&ie_buf[pos-2], NULL, 0) ||
  857. wl_cfgp2p_is_p2p_ie(&ie_buf[pos-2], NULL, 0))) {
  858. CFGP2P_INFO(("DELELED ID : %d, Len : %d , OUI :"
  859. "%02x:%02x:%02x\n", ie_id, ie_len, ie_buf[pos],
  860. ie_buf[pos+1], ie_buf[pos+2]));
  861. ret = wl_cfgp2p_vndr_ie(wl, ndev, bssidx, pktflag,
  862. ie_buf+pos, VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3,
  863. ie_len-3, delete);
  864. }
  865. pos += ie_len;
  866. }
  867. }
  868. *mgmt_ie_len = 0;
  869. /* Add if there is any extra IE */
  870. if (vndr_ie && vndr_ie_len) {
  871. /* save the current IE in wl struct */
  872. memcpy(mgmt_ie_buf, vndr_ie, vndr_ie_len);
  873. *mgmt_ie_len = vndr_ie_len;
  874. pos = 0;
  875. ie_buf = (u8 *) vndr_ie;
  876. delete = 0;
  877. while (pos < vndr_ie_len) {
  878. ie_id = ie_buf[pos++];
  879. ie_len = ie_buf[pos++];
  880. if ((ie_id == DOT11_MNG_VS_ID) &&
  881. (wl_cfgp2p_is_wps_ie(&ie_buf[pos-2], NULL, 0) ||
  882. wl_cfgp2p_is_p2p_ie(&ie_buf[pos-2], NULL, 0))) {
  883. CFGP2P_INFO(("ADDED ID : %d, Len : %d , OUI :"
  884. "%02x:%02x:%02x\n", ie_id, ie_len, ie_buf[pos],
  885. ie_buf[pos+1], ie_buf[pos+2]));
  886. ret = wl_cfgp2p_vndr_ie(wl, ndev, bssidx, pktflag,
  887. ie_buf+pos, VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3,
  888. ie_len-3, delete);
  889. }
  890. pos += ie_len;
  891. }
  892. }
  893. }
  894. #undef IE_TYPE
  895. #undef IE_TYPE_LEN
  896. exit:
  897. return ret;
  898. }
  899. /* Clear the manament IE buffer of BSSCFG
  900. * Parameters:
  901. * @wl : wl_private data
  902. * @bssidx : bssidx for BSS
  903. *
  904. * Returns 0 if success.
  905. */
  906. s32
  907. wl_cfgp2p_clear_management_ie(struct wl_priv *wl, s32 bssidx)
  908. {
  909. #define INIT_IE(IE_TYPE, BSS_TYPE) \
  910. do { \
  911. memset(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \
  912. sizeof(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \
  913. wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \
  914. } while (0);
  915. if (bssidx < 0) {
  916. CFGP2P_ERR(("invalid bssidx\n"));
  917. return BCME_BADARG;
  918. }
  919. INIT_IE(probe_req, bssidx);
  920. INIT_IE(probe_res, bssidx);
  921. INIT_IE(assoc_req, bssidx);
  922. INIT_IE(assoc_res, bssidx);
  923. INIT_IE(beacon, bssidx);
  924. return BCME_OK;
  925. }
  926. /* Is any of the tlvs the expected entry? If
  927. * not update the tlvs buffer pointer/length.
  928. */
  929. static bool
  930. wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type)
  931. {
  932. /* If the contents match the OUI and the type */
  933. if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
  934. !bcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
  935. type == ie[TLV_BODY_OFF + oui_len]) {
  936. return TRUE;
  937. }
  938. if (tlvs == NULL)
  939. return FALSE;
  940. /* point to the next ie */
  941. ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
  942. /* calculate the length of the rest of the buffer */
  943. *tlvs_len -= (int)(ie - *tlvs);
  944. /* update the pointer to the start of the buffer */
  945. *tlvs = ie;
  946. return FALSE;
  947. }
  948. wpa_ie_fixed_t *
  949. wl_cfgp2p_find_wpaie(u8 *parse, u32 len)
  950. {
  951. bcm_tlv_t *ie;
  952. while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) {
  953. if (wl_cfgp2p_is_wpa_ie((u8*)ie, &parse, &len)) {
  954. return (wpa_ie_fixed_t *)ie;
  955. }
  956. }
  957. return NULL;
  958. }
  959. wpa_ie_fixed_t *
  960. wl_cfgp2p_find_wpsie(u8 *parse, u32 len)
  961. {
  962. bcm_tlv_t *ie;
  963. while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) {
  964. if (wl_cfgp2p_is_wps_ie((u8*)ie, &parse, &len)) {
  965. return (wpa_ie_fixed_t *)ie;
  966. }
  967. }
  968. return NULL;
  969. }
  970. wifi_p2p_ie_t *
  971. wl_cfgp2p_find_p2pie(u8 *parse, u32 len)
  972. {
  973. bcm_tlv_t *ie;
  974. while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) {
  975. if (wl_cfgp2p_is_p2p_ie((uint8*)ie, &parse, &len)) {
  976. return (wifi_p2p_ie_t *)ie;
  977. }
  978. }
  979. return NULL;
  980. }
  981. static s32
  982. wl_cfgp2p_vndr_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, s32 pktflag,
  983. s8 *oui, s32 ie_id, s8 *data, s32 data_len, s32 delete)
  984. {
  985. s32 err = BCME_OK;
  986. s32 buf_len;
  987. s32 iecount;
  988. vndr_ie_setbuf_t *ie_setbuf;
  989. /* Validate the pktflag parameter */
  990. if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG |
  991. VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG |
  992. VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG))) {
  993. CFGP2P_ERR(("p2pwl_vndr_ie: Invalid packet flag 0x%x\n", pktflag));
  994. return -1;
  995. }
  996. buf_len = sizeof(vndr_ie_setbuf_t) + data_len - 1;
  997. ie_setbuf = (vndr_ie_setbuf_t *) kzalloc(buf_len, GFP_KERNEL);
  998. CFGP2P_INFO((" ie_id : %02x, data length : %d\n", ie_id, data_len));
  999. if (!ie_setbuf) {
  1000. CFGP2P_ERR(("Error allocating buffer for IE\n"));
  1001. return -ENOMEM;
  1002. }
  1003. if (delete)
  1004. strcpy(ie_setbuf->cmd, "del");
  1005. else
  1006. strcpy(ie_setbuf->cmd, "add");
  1007. /* Buffer contains only 1 IE */
  1008. iecount = htod32(1);
  1009. memcpy((void *)&ie_setbuf->vndr_ie_buffer.iecount, &iecount, sizeof(int));
  1010. pktflag = htod32(pktflag);
  1011. memcpy((void *)&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].pktflag,
  1012. &pktflag, sizeof(uint32));
  1013. ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = ie_id;
  1014. ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len
  1015. = (uchar)(data_len + VNDR_IE_MIN_LEN);
  1016. memcpy(ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, oui, 3);
  1017. memcpy(ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data, data, data_len);
  1018. err = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", ie_setbuf, buf_len,
  1019. wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
  1020. CFGP2P_INFO(("vndr_ie iovar returns %d\n", err));
  1021. kfree(ie_setbuf);
  1022. return err;
  1023. }
  1024. /*
  1025. * Search the bssidx based on dev argument
  1026. * Parameters:
  1027. * @wl : wl_private data
  1028. * @ndev : net device to search bssidx
  1029. * Returns bssidx for ndev
  1030. */
  1031. s32
  1032. wl_cfgp2p_find_idx(struct wl_priv *wl, struct net_device *ndev)
  1033. {
  1034. u32 i;
  1035. s32 index = -1;
  1036. if (ndev == NULL) {
  1037. CFGP2P_ERR((" ndev is NULL\n"));
  1038. goto exit;
  1039. }
  1040. if (!wl->p2p_supported) {
  1041. return P2PAPI_BSSCFG_PRIMARY;
  1042. }
  1043. for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) {
  1044. if (ndev == wl_to_p2p_bss_ndev(wl, i)) {
  1045. index = wl_to_p2p_bss_bssidx(wl, i);
  1046. break;
  1047. }
  1048. }
  1049. if (index == -1)
  1050. return P2PAPI_BSSCFG_PRIMARY;
  1051. exit:
  1052. return index;
  1053. }
  1054. /*
  1055. * Callback function for WLC_E_P2P_DISC_LISTEN_COMPLETE
  1056. */
  1057. s32
  1058. wl_cfgp2p_listen_complete(struct wl_priv *wl, struct net_device *ndev,
  1059. const wl_event_msg_t *e, void *data)
  1060. {
  1061. s32 ret = BCME_OK;
  1062. CFGP2P_DBG((" Enter\n"));
  1063. /* If p2p_info is de-initialized, do nothing */
  1064. if (!wl->p2p)
  1065. return ret;
  1066. if (wl_get_p2p_status(wl, LISTEN_EXPIRED) == 0) {
  1067. wl_set_p2p_status(wl, LISTEN_EXPIRED);
  1068. if (timer_pending(&wl->p2p->listen_timer)) {
  1069. del_timer_sync(&wl->p2p->listen_timer);
  1070. }
  1071. cfg80211_remain_on_channel_expired(ndev, wl->last_roc_id, &wl->remain_on_chan,
  1072. wl->remain_on_chan_type, GFP_KERNEL);
  1073. } else
  1074. wl_clr_p2p_status(wl, LISTEN_EXPIRED);
  1075. return ret;
  1076. }
  1077. /*
  1078. * Timer expire callback function for LISTEN
  1079. * We can't report cfg80211_remain_on_channel_expired from Timer ISR context,
  1080. * so lets do it from thread context.
  1081. */
  1082. static void
  1083. wl_cfgp2p_listen_expired(unsigned long data)
  1084. {
  1085. wl_event_msg_t msg;
  1086. struct wl_priv *wl = (struct wl_priv *) data;
  1087. CFGP2P_DBG((" Enter\n"));
  1088. msg.event_type = hton32(WLC_E_P2P_DISC_LISTEN_COMPLETE);
  1089. wl_cfg80211_event(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE), &msg, NULL);
  1090. }
  1091. /*
  1092. * Routine for cancelling the P2P LISTEN
  1093. */
  1094. s32
  1095. wl_cfgp2p_cancel_listen(struct wl_priv *wl, struct net_device *ndev,
  1096. bool notify)
  1097. {
  1098. WL_DBG(("Enter \n"));
  1099. /* Irrespective of whether timer is running or not, reset
  1100. * the LISTEN state.
  1101. */
  1102. wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0,
  1103. wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
  1104. if (timer_pending(&wl->p2p->listen_timer)) {
  1105. del_timer_sync(&wl->p2p->listen_timer);
  1106. if (notify)
  1107. cfg80211_remain_on_channel_expired(ndev, wl->last_roc_id,
  1108. &wl->remain_on_chan, wl->remain_on_chan_type, GFP_KERNEL);
  1109. }
  1110. return 0;
  1111. }
  1112. /*
  1113. * Do a P2P Listen on the given channel for the given duration.
  1114. * A listen consists of sitting idle and responding to P2P probe requests
  1115. * with a P2P probe response.
  1116. *
  1117. * This fn assumes dongle p2p device discovery is already enabled.
  1118. * Parameters :
  1119. * @wl : wl_private data
  1120. * @channel : channel to listen
  1121. * @duration_ms : the time (milli seconds) to wait
  1122. */
  1123. s32
  1124. wl_cfgp2p_discover_listen(struct wl_priv *wl, s32 channel, u32 duration_ms)
  1125. {
  1126. #define INIT_TIMER(timer, func, duration, extra_delay) \
  1127. do { \
  1128. init_timer(timer); \
  1129. timer->function = func; \
  1130. timer->expires = jiffies + msecs_to_jiffies(duration + extra_delay); \
  1131. timer->data = (unsigned long) wl; \
  1132. add_timer(timer); \
  1133. } while (0);
  1134. s32 ret = BCME_OK;
  1135. struct timer_list *_timer;
  1136. CFGP2P_DBG((" Enter Channel : %d, Duration : %d\n", channel, duration_ms));
  1137. if (unlikely(wl_get_p2p_status(wl, DISCOVERY_ON) == 0)) {
  1138. CFGP2P_ERR((" Discovery is not set, so we have noting to do\n"));
  1139. ret = BCME_NOTREADY;
  1140. goto exit;
  1141. }
  1142. if (timer_pending(&wl->p2p->listen_timer)) {
  1143. CFGP2P_DBG(("previous LISTEN is not completed yet\n"));
  1144. goto exit;
  1145. } else
  1146. wl_clr_p2p_status(wl, LISTEN_EXPIRED);
  1147. wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_LISTEN, channel, (u16) duration_ms,
  1148. wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
  1149. _timer = &wl->p2p->listen_timer;
  1150. /* We will wait to receive WLC_E_P2P_DISC_LISTEN_COMPLETE from dongle ,
  1151. * otherwise we will wait up to duration_ms + 200ms
  1152. */
  1153. INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration_ms, 200);
  1154. #undef INIT_TIMER
  1155. exit:
  1156. return ret;
  1157. }
  1158. s32
  1159. wl_cfgp2p_discover_enable_search(struct wl_priv *wl, u8 enable)
  1160. {
  1161. s32 ret = BCME_OK;
  1162. CFGP2P_DBG((" Enter\n"));
  1163. if (!wl_get_p2p_status(wl, DISCOVERY_ON)) {
  1164. CFGP2P_DBG((" do nothing, discovery is off\n"));
  1165. return ret;
  1166. }
  1167. if (wl_get_p2p_status(wl, SEARCH_ENABLED) == enable) {
  1168. CFGP2P_DBG(("already : %d\n", enable));
  1169. return ret;
  1170. }
  1171. wl_chg_p2p_status(wl, SEARCH_ENABLED);
  1172. /* When disabling Search, reset the WL driver's p2p discovery state to
  1173. * WL_P2P_DISC_ST_SCAN.
  1174. */
  1175. if (!enable) {
  1176. wl_clr_p2p_status(wl, SCANNING);
  1177. ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0,
  1178. wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
  1179. }
  1180. return ret;
  1181. }
  1182. /*
  1183. * Callback function for WLC_E_ACTION_FRAME_COMPLETE, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE
  1184. */
  1185. s32
  1186. wl_cfgp2p_action_tx_complete(struct wl_priv *wl, struct net_device *ndev,
  1187. const wl_event_msg_t *e, void *data)
  1188. {
  1189. s32 ret = BCME_OK;
  1190. u32 event_type = ntoh32(e->event_type);
  1191. u32 status = ntoh32(e->status);
  1192. CFGP2P_DBG((" Enter\n"));
  1193. if (event_type == WLC_E_ACTION_FRAME_COMPLETE) {
  1194. CFGP2P_INFO((" WLC_E_ACTION_FRAME_COMPLETE is received : %d\n", status));
  1195. if (status == WLC_E_STATUS_SUCCESS) {
  1196. wl_set_p2p_status(wl, ACTION_TX_COMPLETED);
  1197. }
  1198. else {
  1199. wl_set_p2p_status(wl, ACTION_TX_NOACK);
  1200. CFGP2P_ERR(("WLC_E_ACTION_FRAME_COMPLETE : NO ACK\n"));
  1201. }
  1202. } else {
  1203. CFGP2P_INFO((" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received,"
  1204. "status : %d\n", status));
  1205. wake_up_interruptible(&wl->netif_change_event);
  1206. }
  1207. return ret;
  1208. }
  1209. /* Send an action frame immediately without doing channel synchronization.
  1210. *
  1211. * This function does not wait for a completion event before returning.
  1212. * The WLC_E_ACTION_FRAME_COMPLETE event will be received when the action
  1213. * frame is transmitted.
  1214. * The WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE event will be received when an
  1215. * 802.11 ack has been received for the sent action frame.
  1216. */
  1217. s32
  1218. wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev,
  1219. wl_af_params_t *af_params, s32 bssidx)
  1220. {
  1221. s32 ret = BCME_OK;
  1222. s32 timeout = 0;
  1223. CFGP2P_INFO(("\n"));
  1224. CFGP2P_INFO(("channel : %u , dwell time : %u\n",
  1225. af_params->channel, af_params->dwell_time));
  1226. wl_clr_p2p_status(wl, ACTION_TX_COMPLETED);
  1227. wl_clr_p2p_status(wl, ACTION_TX_NOACK);
  1228. #define MAX_WAIT_TIME 2000
  1229. if (bssidx == P2PAPI_BSSCFG_PRIMARY)
  1230. bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
  1231. ret = wldev_iovar_setbuf_bsscfg(dev, "actframe", af_params, sizeof(*af_params),
  1232. wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
  1233. if (ret < 0) {
  1234. CFGP2P_ERR((" sending action frame is failed\n"));
  1235. goto exit;
  1236. }
  1237. timeout = wait_event_interruptible_timeout(wl->netif_change_event,
  1238. (wl_get_p2p_status(wl, ACTION_TX_COMPLETED) || wl_get_p2p_status(wl, ACTION_TX_NOACK)),
  1239. msecs_to_jiffies(MAX_WAIT_TIME));
  1240. if (timeout > 0 && wl_get_p2p_status(wl, ACTION_TX_COMPLETED)) {
  1241. CFGP2P_INFO(("tx action frame operation is completed\n"));
  1242. ret = BCME_OK;
  1243. } else {
  1244. ret = BCME_ERROR;
  1245. CFGP2P_INFO(("tx action frame operation is failed\n"));
  1246. }
  1247. exit:
  1248. CFGP2P_INFO((" via act frame iovar : status = %d\n", ret));
  1249. #undef MAX_WAIT_TIME
  1250. return ret;
  1251. }
  1252. /* Generate our P2P Device Address and P2P Interface Address from our primary
  1253. * MAC address.
  1254. */
  1255. void
  1256. wl_cfgp2p_generate_bss_mac(struct ether_addr *primary_addr,
  1257. struct ether_addr *out_dev_addr, struct ether_addr *out_int_addr)
  1258. {
  1259. memset(out_dev_addr, 0, sizeof(*out_dev_addr));
  1260. memset(out_int_addr, 0, sizeof(*out_int_addr));
  1261. /* Generate the P2P Device Address. This consists of the device's
  1262. * primary MAC address with the locally administered bit set.
  1263. */
  1264. memcpy(out_dev_addr, primary_addr, sizeof(*out_dev_addr));
  1265. out_dev_addr->octet[0] |= 0x02;
  1266. /* Generate the P2P Interface Address. If the discovery and connection
  1267. * BSSCFGs need to simultaneously co-exist, then this address must be
  1268. * different from the P2P Device Address.
  1269. */
  1270. memcpy(out_int_addr, out_dev_addr, sizeof(*out_int_addr));
  1271. out_int_addr->octet[4] ^= 0x80;
  1272. }
  1273. /* P2P IF Address change to Virtual Interface MAC Address */
  1274. void
  1275. wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_id)
  1276. {
  1277. wifi_p2p_ie_t *ie = (wifi_p2p_ie_t*) buf;
  1278. u16 len = ie->len;
  1279. u8 *subel;
  1280. u8 subelt_id;
  1281. u16 subelt_len;
  1282. CFGP2P_DBG((" Enter\n"));
  1283. /* Point subel to the P2P IE's subelt field.
  1284. * Subtract the preceding fields (id, len, OUI, oui_type) from the length.
  1285. */
  1286. subel = ie->subelts;
  1287. len -= 4; /* exclude OUI + OUI_TYPE */
  1288. while (len >= 3) {
  1289. /* attribute id */
  1290. subelt_id = *subel;
  1291. subel += 1;
  1292. len -= 1;
  1293. /* 2-byte little endian */
  1294. subelt_len = *subel++;
  1295. subelt_len |= *subel++ << 8;
  1296. len -= 2;
  1297. len -= subelt_len; /* for the remaining subelt fields */
  1298. if (subelt_id == element_id) {
  1299. if (subelt_id == P2P_SEID_INTINTADDR) {
  1300. memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN);
  1301. CFGP2P_INFO(("Intended P2P Interface Address ATTR FOUND\n"));
  1302. } else if (subelt_id == P2P_SEID_DEV_ID) {
  1303. memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN);
  1304. CFGP2P_INFO(("Device ID ATTR FOUND\n"));
  1305. } else if (subelt_id == P2P_SEID_DEV_INFO) {
  1306. memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN);
  1307. CFGP2P_INFO(("Device INFO ATTR FOUND\n"));
  1308. } else if (subelt_id == P2P_SEID_GROUP_ID) {
  1309. memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN);
  1310. CFGP2P_INFO(("GROUP ID ATTR FOUND\n"));
  1311. } return;
  1312. } else {
  1313. CFGP2P_DBG(("OTHER id : %d\n", subelt_id));
  1314. }
  1315. subel += subelt_len;
  1316. }
  1317. }
  1318. /*
  1319. * Check if a BSS is up.
  1320. * This is a common implementation called by most OSL implementations of
  1321. * p2posl_bss_isup(). DO NOT call this function directly from the
  1322. * common code -- call p2posl_bss_isup() instead to allow the OSL to
  1323. * override the common implementation if necessary.
  1324. */
  1325. bool
  1326. wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx)
  1327. {
  1328. s32 result, val;
  1329. bool isup = false;
  1330. s8 getbuf[64];
  1331. /* Check if the BSS is up */
  1332. *(int*)getbuf = -1;
  1333. result = wldev_iovar_getbuf_bsscfg(ndev, "bss", &bsscfg_idx,
  1334. sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0, NULL);
  1335. if (result != 0) {
  1336. CFGP2P_ERR(("'wl bss -C %d' failed: %d\n", bsscfg_idx, result));
  1337. CFGP2P_ERR(("NOTE: this ioctl error is normal "
  1338. "when the BSS has not been created yet.\n"));
  1339. } else {
  1340. val = *(int*)getbuf;
  1341. val = dtoh32(val);
  1342. CFGP2P_INFO(("---wl bss -C %d ==> %d\n", bsscfg_idx, val));
  1343. isup = (val ? TRUE : FALSE);
  1344. }
  1345. return isup;
  1346. }
  1347. /* Bring up or down a BSS */
  1348. s32
  1349. wl_cfgp2p_bss(struct wl_priv *wl, struct net_device *ndev, s32 bsscfg_idx, s32 up)
  1350. {
  1351. s32 ret = BCME_OK;
  1352. s32 val = up ? 1 : 0;
  1353. struct {
  1354. s32 cfg;
  1355. s32 val;
  1356. } bss_setbuf;
  1357. bss_setbuf.cfg = htod32(bsscfg_idx);
  1358. bss_setbuf.val = htod32(val);
  1359. CFGP2P_INFO(("---wl bss -C %d %s\n", bsscfg_idx, up ? "up" : "down"));
  1360. ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
  1361. wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
  1362. if (ret != 0) {
  1363. CFGP2P_ERR(("'bss %d' failed with %d\n", up, ret));
  1364. }
  1365. return ret;
  1366. }
  1367. /* Check if 'p2p' is supported in the driver */
  1368. s32
  1369. wl_cfgp2p_supported(struct wl_priv *wl, struct net_device *ndev)
  1370. {
  1371. s32 ret = BCME_OK;
  1372. s32 p2p_supported = 0;
  1373. ret = wldev_iovar_getint(ndev, "p2p",
  1374. &p2p_supported);
  1375. if (ret < 0) {
  1376. CFGP2P_ERR(("wl p2p error %d\n", ret));
  1377. return 0;
  1378. }
  1379. if (p2p_supported == 1) {
  1380. CFGP2P_INFO(("p2p is supported\n"));
  1381. } else {
  1382. CFGP2P_INFO(("p2p is unsupported\n"));
  1383. p2p_supported = 0;
  1384. }
  1385. return p2p_supported;
  1386. }
  1387. /* Cleanup P2P resources */
  1388. s32
  1389. wl_cfgp2p_down(struct wl_priv *wl)
  1390. {
  1391. wl_cfgp2p_cancel_listen(wl,
  1392. wl->p2p_net ? wl->p2p_net : wl_to_prmry_ndev(wl), TRUE);
  1393. wl_cfgp2p_deinit_priv(wl);
  1394. return 0;
  1395. }
  1396. s32
  1397. wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len)
  1398. {
  1399. s32 ret = -1;
  1400. int count, start, duration;
  1401. wl_p2p_sched_t dongle_noa;
  1402. CFGP2P_DBG((" Enter\n"));
  1403. memset(&dongle_noa, 0, sizeof(dongle_noa));
  1404. if (wl->p2p && wl->p2p->vif_created) {
  1405. wl->p2p->noa.desc[0].start = 0;
  1406. sscanf(buf, "%d %d %d", &count, &start, &duration);
  1407. CFGP2P_DBG(("set_p2p_noa count %d start %d duration %d\n",
  1408. count, start, duration));
  1409. if (count != -1)
  1410. wl->p2p->noa.desc[0].count = count;
  1411. /* supplicant gives interval as start */
  1412. if (start != -1)
  1413. wl->p2p->noa.desc[0].interval = start;
  1414. if (duration != -1)
  1415. wl->p2p->noa.desc[0].duration = duration;
  1416. if (wl->p2p->noa.desc[0].count != 255) {
  1417. wl->p2p->noa.desc[0].start = 200;
  1418. dongle_noa.type = WL_P2P_SCHED_TYPE_REQ_ABS;
  1419. dongle_noa.action = WL_P2P_SCHED_ACTION_GOOFF;
  1420. dongle_noa.option = WL_P2P_SCHED_OPTION_TSFOFS;
  1421. }
  1422. else {
  1423. /* Continuous NoA interval. */
  1424. dongle_noa.action = WL_P2P_SCHED_ACTION_NONE;
  1425. dongle_noa.type = WL_P2P_SCHED_TYPE_ABS;
  1426. if ((wl->p2p->noa.desc[0].interval == 102) ||
  1427. (wl->p2p->noa.desc[0].interval == 100)) {
  1428. wl->p2p->noa.desc[0].start = 100 -
  1429. wl->p2p->noa.desc[0].duration;
  1430. dongle_noa.option = WL_P2P_SCHED_OPTION_BCNPCT;
  1431. }
  1432. else {
  1433. dongle_noa.option = WL_P2P_SCHED_OPTION_NORMAL;
  1434. }
  1435. }
  1436. /* Put the noa descriptor in dongle format for dongle */
  1437. dongle_noa.desc[0].count = htod32(wl->p2p->noa.desc[0].count);
  1438. if (dongle_noa.option == WL_P2P_SCHED_OPTION_BCNPCT) {
  1439. dongle_noa.desc[0].start = htod32(wl->p2p->noa.desc[0].start);
  1440. dongle_noa.desc[0].duration = htod32(wl->p2p->noa.desc[0].duration);
  1441. }
  1442. else {
  1443. dongle_noa.desc[0].start = htod32(wl->p2p->noa.desc[0].start*1000);
  1444. dongle_noa.desc[0].duration = htod32(wl->p2p->noa.desc[0].duration*1000);
  1445. }
  1446. dongle_noa.desc[0].interval = htod32(wl->p2p->noa.desc[0].interval*1000);
  1447. ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION),
  1448. "p2p_noa", &dongle_noa, sizeof(dongle_noa), wl->ioctl_buf, WLC_IOCTL_MAXLEN,
  1449. &wl->ioctl_buf_sync);
  1450. if (ret < 0) {
  1451. CFGP2P_ERR(("fw set p2p_noa failed %d\n", ret));
  1452. }
  1453. }
  1454. else {
  1455. CFGP2P_ERR(("ERROR: set_noa in non-p2p mode\n"));
  1456. }
  1457. return ret;
  1458. }
  1459. s32
  1460. wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int buf_len)
  1461. {
  1462. wifi_p2p_noa_desc_t *noa_desc;
  1463. int len = 0, i;
  1464. char _buf[200];
  1465. CFGP2P_DBG((" Enter\n"));
  1466. buf[0] = '\0';
  1467. if (wl->p2p && wl->p2p->vif_created) {
  1468. if (wl->p2p->noa.desc[0].count || wl->p2p->ops.ops) {
  1469. _buf[0] = 1; /* noa index */
  1470. _buf[1] = (wl->p2p->ops.ops ? 0x80: 0) |
  1471. (wl->p2p->ops.ctw & 0x7f); /* ops + ctw */
  1472. len += 2;
  1473. if (wl->p2p->noa.desc[0].count) {
  1474. noa_desc = (wifi_p2p_noa_desc_t*)&_buf[len];
  1475. noa_desc->cnt_type = wl->p2p->noa.desc[0].count;
  1476. noa_desc->duration = wl->p2p->noa.desc[0].duration;
  1477. noa_desc->interval = wl->p2p->noa.desc[0].interval;
  1478. noa_desc->start = wl->p2p->noa.desc[0].start;
  1479. len += sizeof(wifi_p2p_noa_desc_t);
  1480. }
  1481. if (buf_len <= len * 2) {
  1482. CFGP2P_ERR(("ERROR: buf_len %d in not enough for"
  1483. "returning noa in string format\n", buf_len));
  1484. return -1;
  1485. }
  1486. /* We have to convert the buffer data into ASCII strings */
  1487. for (i = 0; i < len; i++) {
  1488. sprintf(buf, "%02x", _buf[i]);
  1489. buf += 2;
  1490. }
  1491. buf[i*2] = '\0';
  1492. }
  1493. }
  1494. else {
  1495. CFGP2P_ERR(("ERROR: get_noa in non-p2p mode\n"));
  1496. return -1;
  1497. }
  1498. return len * 2;
  1499. }
  1500. s32
  1501. wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int len)
  1502. {
  1503. int ps, ctw;
  1504. int ret = -1;
  1505. s32 legacy_ps;
  1506. CFGP2P_DBG((" Enter\n"));
  1507. if (wl->p2p && wl->p2p->vif_created) {
  1508. sscanf(buf, "%d %d %d", &legacy_ps, &ps, &ctw);
  1509. CFGP2P_DBG((" Enter legacy_ps %d ps %d ctw %d\n", legacy_ps, ps, ctw));
  1510. if (ctw != -1) {
  1511. wl->p2p->ops.ctw = ctw;
  1512. ret = 0;
  1513. }
  1514. if (ps != -1) {
  1515. wl->p2p->ops.ops = ps;
  1516. ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION),
  1517. "p2p_ops", &wl->p2p->ops, sizeof(wl->p2p->ops),
  1518. wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
  1519. if (ret < 0) {
  1520. CFGP2P_ERR(("fw set p2p_ops failed %d\n", ret));
  1521. }
  1522. }
  1523. if (legacy_ps != -1) {
  1524. s32 pm = legacy_ps ? PM_MAX : PM_OFF;
  1525. ret = wldev_ioctl(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION),
  1526. WLC_SET_PM, &pm, sizeof(pm), true);
  1527. if (unlikely(ret)) {
  1528. CFGP2P_ERR(("error (%d)\n", ret));
  1529. }
  1530. }
  1531. }
  1532. else {
  1533. CFGP2P_ERR(("ERROR: set_p2p_ps in non-p2p mode\n"));
  1534. ret = -1;
  1535. }
  1536. return ret;
  1537. }
  1538. u8 *
  1539. wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id)
  1540. {
  1541. wifi_p2p_ie_t *ie = NULL;
  1542. u16 len = 0;
  1543. u8 *subel;
  1544. u8 subelt_id;
  1545. u16 subelt_len;
  1546. if (!buf) {
  1547. WL_ERR(("P2P IE not present"));
  1548. return 0;
  1549. }
  1550. ie = (wifi_p2p_ie_t*) buf;
  1551. len = ie->len;
  1552. /* Point subel to the P2P IE's subelt field.
  1553. * Subtract the preceding fields (id, len, OUI, oui_type) from the length.
  1554. */
  1555. subel = ie->subelts;
  1556. len -= 4; /* exclude OUI + OUI_TYPE */
  1557. while (len >= 3) {
  1558. /* attribute id */
  1559. subelt_id = *subel;
  1560. subel += 1;
  1561. len -= 1;
  1562. /* 2-byte little endian */
  1563. subelt_len = *subel++;
  1564. subelt_len |= *subel++ << 8;
  1565. len -= 2;
  1566. len -= subelt_len; /* for the remaining subelt fields */
  1567. if (subelt_id == element_id) {
  1568. /* This will point to start of subelement attrib after
  1569. * attribute id & len
  1570. */
  1571. return subel;
  1572. }
  1573. /* Go to next subelement */
  1574. subel += subelt_len;
  1575. }
  1576. /* Not Found */
  1577. return NULL;
  1578. }
  1579. #define P2P_GROUP_CAPAB_GO_BIT 0x01
  1580. u8 *
  1581. wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length)
  1582. {
  1583. wifi_p2p_ie_t * p2p_ie = NULL;
  1584. u8 *capability = NULL;
  1585. bool p2p_go = 0;
  1586. u8 *ptr = NULL;
  1587. if (!(p2p_ie = wl_cfgp2p_find_p2pie(((u8 *) bi) + bi->ie_offset, bi->ie_length))) {
  1588. WL_ERR(("P2P IE not found"));
  1589. return NULL;
  1590. }
  1591. if (!(capability = wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_P2P_INFO))) {
  1592. WL_ERR(("P2P Capability attribute not found"));
  1593. return NULL;
  1594. }
  1595. /* Check Group capability for Group Owner bit */
  1596. p2p_go = capability[1] & P2P_GROUP_CAPAB_GO_BIT;
  1597. if (!p2p_go) {
  1598. return bi->BSSID.octet;
  1599. }
  1600. /* In probe responses, DEVICE INFO attribute will be present */
  1601. if (!(ptr = wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_DEV_INFO))) {
  1602. /* If DEVICE_INFO is not found, this might be a beacon frame.
  1603. * check for DEVICE_ID in the beacon frame.
  1604. */
  1605. ptr = wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_DEV_ID);
  1606. }
  1607. if (!ptr)
  1608. WL_ERR((" Both DEVICE_ID & DEVICE_INFO attribute not present in P2P IE "));
  1609. return ptr;
  1610. }
  1611. s32
  1612. wl_cfgp2p_register_ndev(struct wl_priv *wl)
  1613. {
  1614. int ret = 0;
  1615. struct net_device* net = NULL;
  1616. struct wireless_dev *wdev;
  1617. uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x33, 0x22, 0x11 };
  1618. /* Allocate etherdev, including space for private structure */
  1619. if (!(net = alloc_etherdev(sizeof(wl)))) {
  1620. CFGP2P_ERR(("%s: OOM - alloc_etherdev\n", __FUNCTION__));
  1621. goto fail;
  1622. }
  1623. strcpy(net->name, "p2p%d");
  1624. net->name[IFNAMSIZ - 1] = '\0';
  1625. /* Copy the reference to wl_priv */
  1626. memcpy((void *)netdev_priv(net), &wl, sizeof(wl));
  1627. #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
  1628. ASSERT(!net->open);
  1629. net->do_ioctl = wl_cfgp2p_do_ioctl;
  1630. net->hard_start_xmit = wl_cfgp2p_start_xmit;
  1631. net->open = wl_cfgp2p_if_open;
  1632. net->stop = wl_cfgp2p_if_stop;
  1633. #else
  1634. ASSERT(!net->netdev_ops);
  1635. net->netdev_ops = &wl_cfgp2p_if_ops;
  1636. #endif
  1637. /* Register with a dummy MAC addr */
  1638. memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN);
  1639. wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
  1640. if (unlikely(!wdev)) {
  1641. WL_ERR(("Could not allocate wireless device\n"));
  1642. return -ENOMEM;
  1643. }
  1644. wdev->wiphy = wl->wdev->wiphy;
  1645. wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
  1646. net->ieee80211_ptr = wdev;
  1647. SET_NETDEV_DEV(net, wiphy_dev(wdev->wiphy));
  1648. /* Associate p2p0 network interface with new wdev */
  1649. wdev->netdev = net;
  1650. /* store p2p net ptr for further reference. Note that iflist won't have this
  1651. * entry as there corresponding firmware interface is a "Hidden" interface.
  1652. */
  1653. if (wl->p2p_net) {
  1654. CFGP2P_ERR(("p2p_net defined already.\n"));
  1655. return -EINVAL;
  1656. } else {
  1657. wl->p2p_wdev = wdev;
  1658. wl->p2p_net = net;
  1659. }
  1660. ret = register_netdev(net);
  1661. if (ret) {
  1662. CFGP2P_ERR((" register_netdevice failed (%d)\n", ret));
  1663. goto fail;
  1664. }
  1665. printk("%s: P2P Interface Registered\n", net->name);
  1666. return ret;
  1667. fail:
  1668. #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
  1669. net->open = NULL;
  1670. #else
  1671. net->netdev_ops = NULL;
  1672. #endif
  1673. if (net) {
  1674. unregister_netdev(net);
  1675. free_netdev(net);
  1676. }
  1677. return -ENODEV;
  1678. }
  1679. s32
  1680. wl_cfgp2p_unregister_ndev(struct wl_priv *wl)
  1681. {
  1682. if (!wl || !wl->p2p_net) {
  1683. CFGP2P_ERR(("Invalid Ptr\n"));
  1684. return -EINVAL;
  1685. }
  1686. unregister_netdev(wl->p2p_net);
  1687. free_netdev(wl->p2p_net);
  1688. return 0;
  1689. }
  1690. static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev)
  1691. {
  1692. CFGP2P_DBG(("(%s) is not used for data operations. Droping the packet. \n", ndev->name));
  1693. return 0;
  1694. }
  1695. static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd)
  1696. {
  1697. int ret = 0;
  1698. struct wl_priv *wl = *(struct wl_priv **)netdev_priv(net);
  1699. struct net_device *ndev = wl_to_prmry_ndev(wl);
  1700. /* There is no ifidx corresponding to p2p0 in our firmware. So we should
  1701. * not Handle any IOCTL cmds on p2p0 other than ANDROID PRIVATE CMDs.
  1702. * For Android PRIV CMD handling map it to primary I/F
  1703. */
  1704. if (cmd == SIOCDEVPRIVATE+1) {
  1705. ret = wl_android_priv_cmd(ndev, ifr, cmd);
  1706. } else {
  1707. CFGP2P_ERR(("%s: IOCTL req 0x%x on p2p0 I/F. Ignoring. \n",
  1708. __FUNCTION__, cmd));
  1709. return -1;
  1710. }
  1711. return ret;
  1712. }
  1713. static int wl_cfgp2p_if_open(struct net_device *net)
  1714. {
  1715. struct wireless_dev *wdev = net->ieee80211_ptr;
  1716. if (!wdev)
  1717. return -EINVAL;
  1718. /* If suppose F/W download (ifconfig wlan0 up) hasn't been done by now,
  1719. * do it here. This will make sure that in concurrent mode, supplicant
  1720. * is not dependent on a particular order of interface initialization.
  1721. * i.e you may give wpa_supp -iwlan0 -N -ip2p0 or wpa_supp -ip2p0 -N
  1722. * -iwlan0.
  1723. */
  1724. wl_cfg80211_do_driver_init(net);
  1725. wdev->wiphy->interface_modes |= (BIT(NL80211_IFTYPE_P2P_CLIENT)
  1726. | BIT(NL80211_IFTYPE_P2P_GO));
  1727. return 0;
  1728. }
  1729. static int wl_cfgp2p_if_stop(struct net_device *net)
  1730. {
  1731. struct wireless_dev *wdev = net->ieee80211_ptr;
  1732. if (!wdev)
  1733. return -EINVAL;
  1734. wdev->wiphy->interface_modes = (wdev->wiphy->interface_modes)
  1735. & (~(BIT(NL80211_IFTYPE_P2P_CLIENT)|
  1736. BIT(NL80211_IFTYPE_P2P_GO)));
  1737. return 0;
  1738. }