/* * pack xtlv buffer from memory according to xtlv_desc_t */ int bcm_pack_xtlv_buf_from_mem(void **tlv_buf, uint16 *buflen, xtlv_desc_t *items) { int res = 0; void *ptlv = *tlv_buf; while (items->len != 0) { if ((res = bcm_pack_xtlv_entry(&ptlv, buflen, items->type, items->len, items->ptr) != BCME_OK)) { break; } items++; } *tlv_buf = ptlv; /* update the external pointer */ return res; }
int wl_cfgnan_transmit_handler(struct net_device *ndev, struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) { wl_nan_ioc_t *nanioc = NULL; void *pxtlv; s32 ret = BCME_OK; u16 start, end; u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; /* * proceed only if mandatory arguments are present - subscriber id, * publisher id, mac address */ if ((!cmd_data->sub_id) || (!cmd_data->pub_id) || ETHER_ISNULLADDR(&cmd_data->mac_addr.octet)) { WL_ERR((" mandatory arguments are not present \n")); return -EINVAL; } nanioc = kzalloc(nanioc_size, kflags); if (!nanioc) { WL_ERR((" memory allocation failed \n")); return -ENOMEM; } /* * command to test * * wl: wl nan trasnmit <sub_id> <pub_id> <mac_addr> -info <hex_string> * * wpa_cli: DRIVER NAN_TRANSMIT SUB_ID=<sub_id> PUB_ID=<pub_id> * MAC_ADDR=<mac_addr> SVC_INFO=<hex_string> */ /* nan transmit */ start = end = NAN_IOCTL_BUF_SIZE; nanioc->version = htod16(WL_NAN_IOCTL_VERSION); nanioc->id = htod16(WL_NAN_CMD_TRANSMIT); pxtlv = nanioc->data; ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_INSTANCE_ID, sizeof(wl_nan_instance_id_t), &cmd_data->sub_id); if (unlikely(ret)) { goto fail; } ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_REQUESTOR_ID, sizeof(wl_nan_instance_id_t), &cmd_data->pub_id); if (unlikely(ret)) { goto fail; } ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_MAC_ADDR, ETHER_ADDR_LEN, &cmd_data->mac_addr.octet); if (unlikely(ret)) { goto fail; } if (cmd_data->svc_info.data && cmd_data->svc_info.dlen) { WL_DBG((" optional svc_info present, pack it \n")); ret = bcm_pack_xtlv_entry_from_hex_string(&pxtlv, &end, WL_NAN_XTLV_SVC_INFO, cmd_data->svc_info.data); if (unlikely(ret)) { goto fail; } } nanioc->len = start - end; nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); if (unlikely(ret)) { WL_ERR((" nan transmit failed, error = %d \n", ret)); goto fail; } else { WL_DBG((" nan transmit successful \n")); } fail: if (nanioc) { kfree(nanioc); } return ret; }
int wl_cfgnan_pub_handler(struct net_device *ndev, struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) { wl_nan_ioc_t *nanioc = NULL; struct bcm_tlvbuf *tbuf = NULL; wl_nan_disc_params_t params; s32 ret = BCME_OK; u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; uint16 tbuf_size = BCM_XTLV_HDR_SIZE + sizeof(params); uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; void *pxtlv; u16 start, end; /* * proceed only if mandatory arguments are present - publisher id, * service hash */ if ((!cmd_data->pub_id) || (!cmd_data->svc_hash.data) || (!cmd_data->svc_hash.dlen)) { WL_ERR((" mandatory arguments are not present \n")); return -EINVAL; } nanioc = kzalloc(nanioc_size, kflags); if (!nanioc) { WL_ERR((" memory allocation failed \n")); return -ENOMEM; } tbuf = bcm_xtlv_buf_alloc(NULL, tbuf_size); if (!tbuf) { WL_ERR((" memory allocation failed \n")); ret = -ENOMEM; goto fail; } /* * command to test * * wl: wl nan publish 10 NAN123 -info <hex_string * wl nan publish 10 NAN123 -info <hex_string -period 1 -ttl 0xffffffff * * wpa_cli: DRIVER NAN_PUBLISH PUB_ID=10 SVC_HASH=NAN123 * SVC_INFO=<hex_string> * DRIVER NAN_PUBLISH PUB_ID=10 SVC_HASH=NAN123 * SVC_INFO=<hex_string> PUB_PR=1 PUB_INT=0xffffffff */ /* nan publish */ start = end = NAN_IOCTL_BUF_SIZE; nanioc->version = htod16(WL_NAN_IOCTL_VERSION); nanioc->id = htod16(WL_NAN_CMD_PUBLISH); pxtlv = nanioc->data; /* disovery parameters */ if (cmd_data->pub_pr) { params.period = cmd_data->pub_pr; } else { params.period = 1; } if (cmd_data->pub_int) { params.ttl = cmd_data->pub_int; } else { params.ttl = WL_NAN_TTL_UNTIL_CANCEL; } params.flags = WL_NAN_PUB_BOTH; params.instance_id = (wl_nan_instance_id_t)cmd_data->pub_id; memcpy((char *)params.svc_hash, cmd_data->svc_hash.data, cmd_data->svc_hash.dlen); ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_SVC_PARAMS, sizeof(wl_nan_disc_params_t), ¶ms); if (unlikely(ret)) { goto fail; } if (cmd_data->svc_info.data && cmd_data->svc_info.dlen) { WL_DBG((" optional svc_info present, pack it \n")); ret = bcm_pack_xtlv_entry_from_hex_string(&pxtlv, &end, WL_NAN_XTLV_SVC_INFO, cmd_data->svc_info.data); if (unlikely(ret)) { goto fail; } } nanioc->len = start - end; nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); if (unlikely(ret)) { WL_ERR((" nan publish failed, error = %d \n", ret)); goto fail; } else { WL_DBG((" nan publish successful \n")); } fail: if (tbuf) { bcm_xtlv_buf_free(NULL, tbuf); } if (nanioc) { kfree(nanioc); } return ret; }
int wl_cfgnan_stop_handler(struct net_device *ndev, struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) { wl_nan_ioc_t *nanioc = NULL; struct ether_addr cluster_id = ether_null; void *pxtlv; s32 ret = BCME_OK; u16 start, end; u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; uint8 nan_enable = FALSE; if (cfg->nan_running == false) { WL_DBG((" nan not running, do nothing \n")); return BCME_OK; } nanioc = kzalloc(nanioc_size, kflags); if (!nanioc) { WL_ERR((" memory allocation failed \n")); return -ENOMEM; } /* * command to test * * wl: wl nan stop * wl nan 0 * * wpa_cli: DRIVER NAN_STOP */ /* nan stop */ start = end = NAN_IOCTL_BUF_SIZE; nanioc->version = htod16(WL_NAN_IOCTL_VERSION); nanioc->id = htod16(WL_NAN_CMD_STOP); pxtlv = nanioc->data; ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_CLUSTER_ID, ETHER_ADDR_LEN, &cluster_id); if (unlikely(ret)) { goto fail; } nanioc->len = start - end; nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); if (unlikely(ret)) { WL_ERR((" nan stop failed, error = %d \n", ret)); goto fail; } else { WL_DBG((" nan stop successful \n")); } /* nan disable */ memset(nanioc, 0, nanioc_size); start = end = NAN_IOCTL_BUF_SIZE; nanioc->version = htod16(WL_NAN_IOCTL_VERSION); nanioc->id = htod16(WL_NAN_CMD_ENABLE); pxtlv = nanioc->data; ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_ENABLE, sizeof(uint8), &nan_enable); if (unlikely(ret)) { goto fail; } nanioc->len = start - end; nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); if (unlikely(ret)) { WL_ERR((" nan disable failed, error = %d \n", ret)); goto fail; } else { WL_DBG((" nan disable successful \n")); } fail: if (nanioc) { kfree(nanioc); } return ret; }
int wl_cfgnan_enable_events(struct net_device *ndev, struct bcm_cfg80211 *cfg) { wl_nan_ioc_t *nanioc = NULL; void *pxtlv; u32 event_mask = 0; s32 ret = BCME_OK; u16 start, end; u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; nanioc = kzalloc(nanioc_size, kflags); if (!nanioc) { WL_ERR((" memory allocation failed \n")); return -ENOMEM; } ret = wl_add_remove_eventmsg(ndev, WLC_E_NAN, true); if (unlikely(ret)) { WL_ERR((" nan event enable failed, error = %d \n", ret)); goto fail; } if (g_nan_debug) { /* enable all nan events */ event_mask = NAN_EVENT_MASK_ALL; } else { /* enable only selected nan events to avoid unnecessary host wake up */ event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_START); event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_JOIN); event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_DISCOVERY_RESULT); event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_RECEIVE); event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_TERMINATED); event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_STOP); event_mask |= NAN_EVENT_BIT(WL_NAN_EVENT_CLEAR_BIT); event_mask = htod32(event_mask); } start = end = NAN_IOCTL_BUF_SIZE; nanioc->version = htod16(WL_NAN_IOCTL_VERSION); nanioc->id = htod16(WL_NAN_CMD_EVENT_MASK); pxtlv = nanioc->data; ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_EVENT_MASK, sizeof(uint32), &event_mask); if (unlikely(ret)) { goto fail; } nanioc->len = start - end; nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); if (unlikely(ret)) { WL_ERR((" nan event selective enable failed, error = %d \n", ret)); goto fail; } else { WL_DBG((" nan event selective enable successful \n")); } ret = wl_add_remove_eventmsg(ndev, WLC_E_PROXD, true); if (unlikely(ret)) { WL_ERR((" proxd event enable failed, error = %d \n", ret)); goto fail; } fail: if (nanioc) { kfree(nanioc); } return ret; }
int wl_cfgnan_set_config_handler(struct net_device *ndev, struct bcm_cfg80211 *cfg, char *cmd, nan_cmd_data_t *cmd_data) { wl_nan_ioc_t *nanioc = NULL; void *pxtlv; s32 ret = BCME_OK; u16 start, end; u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; uint16 nanioc_size = sizeof(wl_nan_ioc_t) + NAN_IOCTL_BUF_SIZE; nanioc = kzalloc(nanioc_size, kflags); if (!nanioc) { WL_ERR((" memory allocation failed \n")); return -ENOMEM; } /* * command to test * * wl: wl nan <attr> <value> (wl nan role 1) * * wpa_cli: DRIVER NAN_CONFIG_SET ATTR=<attr> <value>...<value> * * wpa_cli: DRIVER NAN_SET_CONFIG ATTR=ATTR_ROLE ROLE=1 */ /* nan set config */ start = end = NAN_IOCTL_BUF_SIZE; nanioc->version = htod16(WL_NAN_IOCTL_VERSION); nanioc->id = htod16(WL_NAN_CMD_ATTR); pxtlv = nanioc->data; switch (cmd_data->attr.type) { case WL_NAN_XTLV_ROLE: ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_ROLE, sizeof(u32), &cmd_data->role); break; case WL_NAN_XTLV_MASTER_PREF: ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_MASTER_PREF, sizeof(u16), &cmd_data->master_pref); break; case WL_NAN_XTLV_DW_LEN: ret = bcm_pack_xtlv_entry(&pxtlv, &end, WL_NAN_XTLV_DW_LEN, sizeof(u16), &cmd_data->dw_len); break; case WL_NAN_XTLV_CLUSTER_ID: case WL_NAN_XTLV_IF_ADDR: case WL_NAN_XTLV_BCN_INTERVAL: case WL_NAN_XTLV_MAC_CHANSPEC: case WL_NAN_XTLV_MAC_TXRATE: default: ret = -EINVAL; break; } if (unlikely(ret)) { WL_ERR((" unsupported attribute, attr = %s (%d) \n", cmd_data->attr.name, cmd_data->attr.type)); goto fail; } nanioc->len = start - end; nanioc_size = sizeof(wl_nan_ioc_t) + nanioc->len; ret = wldev_iovar_setbuf(ndev, "nan", nanioc, nanioc_size, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); if (unlikely(ret)) { WL_ERR((" nan set config failed, error = %d \n", ret)); goto fail; } else { WL_DBG((" nan set config successful \n")); } fail: if (nanioc) { kfree(nanioc); } return ret; }