| /***************************************************************************** |
| * |
| * Copyright (c) 2012 - 2021 Samsung Electronics Co., Ltd. All rights reserved |
| * |
| ****************************************************************************/ |
| |
| #include "debug.h" |
| #include "mlme.h" |
| #include "nl80211_vendor_nan.h" |
| |
| #define SLSI_FAPI_NAN_ATTRIBUTE_PUT_U8(req, attribute, val) \ |
| { \ |
| u16 attribute_len = 1; \ |
| struct sk_buff *req_p = req; \ |
| fapi_append_data((req_p), (u8 *)&(attribute), 2); \ |
| fapi_append_data((req_p), (u8 *)&attribute_len, 2); \ |
| fapi_append_data((req_p), (u8 *)&(val), 1); \ |
| } |
| |
| #define SLSI_FAPI_NAN_ATTRIBUTE_PUT_U16(req, attribute, val) \ |
| { \ |
| u16 attribute_len = 2; \ |
| __le16 le16val = cpu_to_le16(val); \ |
| struct sk_buff *req_p = req; \ |
| fapi_append_data((req_p), (u8 *)&(attribute), 2); \ |
| fapi_append_data((req_p), (u8 *)&attribute_len, 2); \ |
| fapi_append_data((req_p), (u8 *)&le16val, 2); \ |
| } |
| |
| #define SLSI_FAPI_NAN_ATTRIBUTE_PUT_U32(req, attribute, val) \ |
| { \ |
| u16 attribute_len = 4; \ |
| __le32 le32val = cpu_to_le32(val);\ |
| struct sk_buff *req_p = req; \ |
| fapi_append_data((req_p), (u8 *)&(attribute), 2); \ |
| fapi_append_data((req_p), (u8 *)&attribute_len, 2); \ |
| fapi_append_data((req_p), (u8 *)&le32val, 4); \ |
| } |
| |
| #define SLSI_FAPI_NAN_ATTRIBUTE_PUT_DATA(req, attribute, val, val_len) \ |
| { \ |
| u16 attribute_len = (val_len); \ |
| struct sk_buff *req_p = req; \ |
| fapi_append_data((req_p), (u8 *)&(attribute), 2); \ |
| fapi_append_data((req_p), (u8 *)&attribute_len, 2); \ |
| fapi_append_data((req_p), (val), (attribute_len)); \ |
| } |
| |
| static u32 slsi_mlme_nan_append_tlv(struct sk_buff *req, u16 tag, u16 len, u8 *data) |
| { |
| u8 *p; |
| |
| p = fapi_append_data_u16(req, tag); |
| p = fapi_append_data_u16(req, len); |
| p = fapi_append_data(req, data, len); |
| if (p) |
| return 0; |
| return 1; |
| } |
| |
| static u32 slsi_mlme_nan_append_service_info_tlv(struct sk_buff *req, struct slsi_hal_nan_data_path_app_info *app_info) |
| { |
| int pos = 0; |
| u16 length; |
| int ret = 1; |
| |
| while (pos < (app_info->ndp_app_info_len - 3)) { |
| length = app_info->ndp_app_info[pos + 2] << 8 | app_info->ndp_app_info[pos + 1]; |
| if (app_info->ndp_app_info[pos] == 0x01) { |
| if ((length + pos + 3) <= app_info->ndp_app_info_len) |
| ret = slsi_mlme_nan_append_tlv(req, SLSI_NAN_TLV_WFA_SERVICE_INFO, length, |
| &app_info->ndp_app_info[pos + 3]); |
| break; |
| } |
| pos = pos + length + 3; //Length is 2 bytes and tag is 1 byte |
| } |
| return ret; |
| } |
| |
| static u16 slsi_mlme_nan_service_info_tlv_length(struct slsi_hal_nan_data_path_app_info *app_info) |
| { |
| int pos = 0; |
| u16 length = 0; |
| |
| while (pos < (app_info->ndp_app_info_len - 3)) { |
| if (app_info->ndp_app_info[pos] == 0x01) { |
| length = app_info->ndp_app_info[pos + 2] << 8 | app_info->ndp_app_info[pos + 1]; |
| break; |
| } |
| //Length is 2 bytes and tag is 1 byte |
| pos = pos + app_info->ndp_app_info[pos + 1] + 3; |
| } |
| return length; |
| } |
| |
| static u32 slsi_mlme_nan_append_config_tlv(struct sk_buff *req, u8 master_pref, u16 include_ps_id, u8 ps_id_count, |
| u16 include_ss_id, u8 ss_id_count, u16 rssi_window, u32 nmi_rand_interval, |
| u16 cluster_merge) |
| { |
| u8 *p; |
| |
| p = fapi_append_data_u16(req, SLSI_NAN_TLV_TAG_CONFIGURATION); |
| p = fapi_append_data_u16(req, 0x000f); |
| p = fapi_append_data_u8(req, master_pref); |
| |
| /* publish service ID inclusion in beacon */ |
| p = fapi_append_data_bool(req, include_ps_id); |
| p = fapi_append_data_u8(req, ps_id_count); |
| |
| /* subscribe service ID inclusion in beacon */ |
| p = fapi_append_data_bool(req, include_ss_id); |
| p = fapi_append_data_u8(req, ss_id_count); |
| |
| p = fapi_append_data_u16(req, rssi_window); |
| p = fapi_append_data_u32(req, nmi_rand_interval); |
| p = fapi_append_data_u16(req, cluster_merge); |
| |
| if (p) |
| return 0; |
| return 1; |
| } |
| |
| static u32 slsi_mlme_nan_append_band_specific_config(struct sk_buff *req, u16 tag, u8 rssi_close, u8 rssi_middle, |
| u8 rssi_proximity, u8 dwell_time, u16 scan_period, |
| u16 use_dw_int_val, u8 dw_interval) |
| { |
| u8 *p; |
| |
| p = fapi_append_data_u16(req, tag); |
| p = fapi_append_data_u16(req, 0x0009); |
| p = fapi_append_data_u8(req, rssi_close); |
| p = fapi_append_data_u8(req, rssi_middle); |
| p = fapi_append_data_u8(req, rssi_proximity); |
| p = fapi_append_data_u8(req, dwell_time); |
| p = fapi_append_data_u16(req, scan_period); |
| p = fapi_append_data_bool(req, use_dw_int_val); |
| p = fapi_append_data_u8(req, dw_interval); |
| if (p) |
| return 0; |
| return 1; |
| } |
| |
| static u32 slsi_mlme_nan_append_2g4_band_specific_config(struct sk_buff *req, u8 rssi_close, u8 rssi_middle, |
| u8 rssi_proximity, u8 dwell_time, u16 scan_period, |
| u16 use_dw_int_val, u8 dw_interval) |
| { |
| return slsi_mlme_nan_append_band_specific_config(req, SLSI_NAN_TLV_TAG_2G4_BAND_SPECIFIC_CONFIG, rssi_close, |
| rssi_middle, rssi_proximity, dwell_time, scan_period, |
| use_dw_int_val, dw_interval); |
| } |
| |
| static u32 slsi_mlme_nan_append_5g_band_specific_config(struct sk_buff *req, u8 rssi_close, u8 rssi_middle, |
| u8 rssi_proximity, u8 dwell_time, u16 scan_period, |
| u16 use_dw_int_val, u8 dw_interval) |
| { |
| return slsi_mlme_nan_append_band_specific_config(req, SLSI_NAN_TLV_TAG_5G_BAND_SPECIFIC_CONFIG, rssi_close, |
| rssi_middle, rssi_proximity, dwell_time, scan_period, |
| use_dw_int_val, dw_interval); |
| } |
| |
| static u32 slsi_mlme_nan_append_config_supplemental(struct sk_buff *req, u32 db_interval_ms, u32 nss_discovery, |
| u32 enable_dw_early_termination, u32 enable_ranging) |
| { |
| u8 *p; |
| |
| p = fapi_append_data_u16(req, SLSI_NAN_TLV_TAG_CONFIG_SUPPLEMENTAL); |
| p = fapi_append_data_u16(req, 0x0007); |
| p = fapi_append_data_u16(req, db_interval_ms); |
| p = fapi_append_data_u8(req, nss_discovery); |
| p = fapi_append_data_bool(req, enable_dw_early_termination); |
| p = fapi_append_data_bool(req, enable_ranging); |
| if (p) |
| return 0; |
| return 1; |
| } |
| |
| static u32 slsi_mlme_nan_append_discovery_config(struct sk_buff *req, u8 sd_type, u8 tx_type, u16 ttl, u16 dw_period, |
| u8 dw_count, u8 disc_match_ind, u16 use_rssi_thres, u16 ranging_req, |
| u16 data_path_req) |
| { |
| u8 *p; |
| |
| p = fapi_append_data_u16(req, SLSI_NAN_TLV_TAG_DISCOVERY_COMMON_SPECIFIC); |
| p = fapi_append_data_u16(req, 0x000e); |
| p = fapi_append_data_u8(req, sd_type); |
| p = fapi_append_data_u8(req, tx_type); |
| p = fapi_append_data_u16(req, ttl); |
| p = fapi_append_data_u16(req, dw_period); |
| p = fapi_append_data_u8(req, dw_count); |
| p = fapi_append_data_u8(req, disc_match_ind); |
| p = fapi_append_data_bool(req, use_rssi_thres); |
| p = fapi_append_data_bool(req, ranging_req); |
| p = fapi_append_data_bool(req, data_path_req); |
| if (p) |
| return 0; |
| return 1; |
| } |
| |
| static u32 slsi_mlme_nan_append_subscribe_specific(struct sk_buff *req, u8 srf_type, u16 respond_if_in_address_set, |
| u16 use_srf, u16 ssi_required_for_match) |
| { |
| u8 *p; |
| |
| p = fapi_append_data_u16(req, SLSI_NAN_TLV_TAG_SUBSCRIBE_SPECIFIC); |
| p = fapi_append_data_u16(req, 0x0007); |
| p = fapi_append_data_u8(req, srf_type); |
| p = fapi_append_data_u16(req, respond_if_in_address_set); |
| p = fapi_append_data_u16(req, use_srf); |
| p = fapi_append_data_u16(req, ssi_required_for_match); |
| if (p) |
| return 0; |
| return 1; |
| } |
| |
| static u32 slsi_mlme_nan_append_address_set(struct sk_buff *req, u16 count, u8 *addresses) |
| { |
| if (!count) |
| return 0; |
| return slsi_mlme_nan_append_tlv(req, SLSI_NAN_TLV_TAG_INTERFACE_ADDRESS_SET, count * 6, addresses); |
| } |
| |
| static u32 slsi_mlme_nan_append_service_name(struct sk_buff *req, u16 len, u8 *data) |
| { |
| if (!len) |
| return 0; |
| return slsi_mlme_nan_append_tlv(req, SLSI_NAN_TLV_TAG_SERVICE_NAME, len, data); |
| } |
| |
| static u32 slsi_mlme_nan_append_service_specific_info(struct sk_buff *req, u16 len, u8 *data) |
| { |
| if (!len) |
| return 0; |
| return slsi_mlme_nan_append_tlv(req, SLSI_NAN_TLV_TAG_SERVICE_SPECIFIC_INFO, len, data); |
| } |
| |
| static u32 slsi_mlme_nan_append_ext_service_specific_info(struct sk_buff *req, u16 len, u8 *data) |
| { |
| if (!len) |
| return 0; |
| return slsi_mlme_nan_append_tlv(req, SLSI_NAN_TLV_TAG_EXT_SERVICE_SPECIFIC_INFO, len, data); |
| } |
| |
| static u32 slsi_mlme_nan_append_tx_match_filter(struct sk_buff *req, u16 len, u8 *data) |
| { |
| if (!len) |
| return 0; |
| return slsi_mlme_nan_append_tlv(req, SLSI_NAN_TLV_TAG_TX_MATCH_FILTER, len, data); |
| } |
| |
| static u32 slsi_mlme_nan_append_rx_match_filter(struct sk_buff *req, u16 len, u8 *data) |
| { |
| if (!len) |
| return 0; |
| return slsi_mlme_nan_append_tlv(req, SLSI_NAN_TLV_TAG_RX_MATCH_FILTER, len, data); |
| } |
| |
| static u32 slsi_mlme_nan_append_data_path_sec(struct sk_buff *req, struct slsi_nan_security_info *sec_info) |
| { |
| u8 *p, *len_p; |
| u8 *pmk; |
| u8 passphrase_len = 0; |
| u8 *passphrase; |
| u8 sec_type = sec_info->key_info.key_type; |
| u8 pmk_len = 0; |
| |
| if (sec_info->key_info.key_type == 1) { |
| pmk_len = sec_info->key_info.body.pmk_info.pmk_len; |
| pmk = sec_info->key_info.body.pmk_info.pmk; |
| } else if (sec_info->key_info.key_type == 2) { |
| passphrase_len = sec_info->key_info.body.passphrase_info.passphrase_len; |
| passphrase = sec_info->key_info.body.passphrase_info.passphrase; |
| } else { |
| sec_type = 0; |
| } |
| |
| p = fapi_append_data_u16(req, SLSI_NAN_TLV_TAG_DATA_PATH_SECURITY); |
| p = fapi_append_data_u16(req, 0x0002); |
| len_p = p; |
| p = fapi_append_data_u8(req, sec_type); |
| p = fapi_append_data_u8(req, sec_info->cipher_type); |
| if (sec_info->key_info.key_type == 1) { |
| if (pmk_len) |
| p = fapi_append_data(req, pmk, pmk_len); |
| if (p && len_p) |
| *len_p = 2 + pmk_len; |
| } else if (sec_info->key_info.key_type == 2) { |
| if (passphrase_len) |
| p = fapi_append_data(req, passphrase, passphrase_len); |
| if (p && len_p) |
| *len_p = 2 + passphrase_len; |
| } |
| if (!p) |
| return 1; |
| return 0; |
| } |
| |
| static u32 slsi_mlme_nan_append_ranging(struct sk_buff *req, struct slsi_nan_ranging_cfg *ranging_cfg) |
| { |
| u8 *p; |
| |
| p = fapi_append_data_u16(req, SLSI_NAN_TLV_TAG_RANGING); |
| p = fapi_append_data_u16(req, 0x000d); |
| p = fapi_append_data_u32(req, ranging_cfg->ranging_interval_msec); |
| p = fapi_append_data_u8(req, ranging_cfg->config_ranging_indications); |
| p = fapi_append_data_u32(req, ranging_cfg->distance_ingress_mm); |
| p = fapi_append_data_u32(req, ranging_cfg->distance_egress_mm); |
| if (p) |
| return 0; |
| return 1; |
| } |
| |
| static int slsi_mlme_nan_append_ipv6_link_tlv(struct sk_buff *req, u8 *local_ndi) |
| { |
| u8 *p; |
| u8 interface_identifier[8]; |
| |
| memcpy(&interface_identifier[0], &local_ndi[0], 3); |
| interface_identifier[3] = 0xFF; |
| interface_identifier[4] = 0xFE; |
| memcpy(&interface_identifier[5], &local_ndi[3], 3); |
| |
| p = fapi_append_data_u16(req, SLSI_NAN_TLV_WFA_IPV6_LOCAL_LINK); |
| p = fapi_append_data_u16(req, 0x0008); |
| p = fapi_append_data(req, interface_identifier, 8); |
| |
| if (p) |
| return 0; |
| return 1; |
| } |
| |
| static u32 slsi_mlme_nan_enable_fapi_data(struct netdev_vif *ndev_vif, struct sk_buff *req, struct slsi_hal_nan_enable_req *hal_req, |
| u8 cluster_merge) |
| { |
| u16 publish_id_inc, service_id_inc; |
| u8 publish_id_inc_count = 0; |
| u8 service_id_inc_count = 0; |
| u8 rssi_close, rssi_middle, rssi_proximity; |
| u16 rssi_window = hal_req->config_rssi_window_size ? hal_req->rssi_window_size_val : 8; |
| u32 ret; |
| |
| /* NAN configuration TLV */ |
| publish_id_inc = hal_req->config_sid_beacon && (hal_req->sid_beacon_val & 0x01); |
| if (publish_id_inc) |
| publish_id_inc_count = hal_req->sid_beacon_val >> 1; |
| service_id_inc = hal_req->config_subscribe_sid_beacon && (hal_req->subscribe_sid_beacon_val & 0x01); |
| if (service_id_inc) |
| service_id_inc_count = hal_req->subscribe_sid_beacon_val >> 1; |
| ret = slsi_mlme_nan_append_config_tlv(req, hal_req->master_pref, publish_id_inc, publish_id_inc_count, |
| service_id_inc, service_id_inc_count, rssi_window, |
| hal_req->disc_mac_addr_rand_interval_sec, cluster_merge); |
| if (ret) { |
| SLSI_WARN_NODEV("Error append config TLV\n"); |
| return ret; |
| } |
| |
| /* 2.4G NAN band specific config TLV*/ |
| rssi_close = hal_req->config_2dot4g_rssi_close ? hal_req->rssi_close_2dot4g_val : 0; |
| rssi_middle = hal_req->config_2dot4g_rssi_middle ? hal_req->rssi_middle_2dot4g_val : 0; |
| rssi_proximity = hal_req->config_2dot4g_rssi_proximity ? hal_req->rssi_proximity_2dot4g_val : 0; |
| ret = slsi_mlme_nan_append_2g4_band_specific_config(req, rssi_close, rssi_middle, rssi_proximity, |
| hal_req->scan_params_val.dwell_time[0], |
| hal_req->scan_params_val.scan_period[0], |
| (u16)hal_req->config_2dot4g_dw_band, |
| hal_req->dw_2dot4g_interval_val); |
| if (ret) { |
| SLSI_WARN_NODEV("Error append 2.4G band specific TLV\n"); |
| return ret; |
| } |
| |
| /* 5G NAN band specific config TLV*/ |
| if (hal_req->config_support_5g && hal_req->support_5g_val) { |
| rssi_close = hal_req->config_5g_rssi_close ? hal_req->rssi_close_5g_val : 0; |
| rssi_middle = hal_req->config_5g_rssi_middle ? hal_req->rssi_middle_5g_val : 0; |
| rssi_proximity = hal_req->config_5g_rssi_close_proximity ? hal_req->rssi_close_proximity_5g_val : 0; |
| ret = slsi_mlme_nan_append_5g_band_specific_config(req, rssi_close, rssi_middle, rssi_proximity, |
| hal_req->scan_params_val.dwell_time[1], |
| hal_req->scan_params_val.scan_period[1], |
| (u16)hal_req->config_5g_dw_band, |
| hal_req->dw_5g_interval_val); |
| if (ret) { |
| SLSI_WARN_NODEV("Error append 5G band specific TLV\n"); |
| return ret; |
| } |
| } |
| |
| ret = slsi_mlme_nan_append_config_supplemental(req, hal_req->discovery_beacon_interval_ms, |
| hal_req->nss_discovery, hal_req->enable_dw_early_termination, |
| hal_req->enable_ranging); |
| if (ret) { |
| SLSI_WARN_NODEV("Failed to add config supplemental TLV\n"); |
| return ret; |
| } |
| |
| return ret; |
| } |
| |
| void slsi_mlme_nan_store_config(struct netdev_vif *ndev_vif, struct slsi_hal_nan_enable_req *hal_req) |
| { |
| ndev_vif->nan.config.config_rssi_proximity = hal_req->config_2dot4g_rssi_proximity; |
| ndev_vif->nan.config.rssi_close_2dot4g_val = hal_req->rssi_close_2dot4g_val; |
| ndev_vif->nan.config.rssi_middle_2dot4g_val = hal_req->rssi_middle_2dot4g_val; |
| ndev_vif->nan.config.rssi_proximity = hal_req->rssi_proximity_2dot4g_val; |
| ndev_vif->nan.config.scan_params_val.dwell_time[0] = hal_req->scan_params_val.dwell_time[0]; |
| ndev_vif->nan.config.scan_params_val.scan_period[0] = hal_req->scan_params_val.scan_period[0]; |
| ndev_vif->nan.config.config_2dot4g_dw_band = (u16)hal_req->config_2dot4g_dw_band; |
| ndev_vif->nan.config.dw_2dot4g_interval_val = hal_req->dw_2dot4g_interval_val; |
| |
| ndev_vif->nan.config.config_5g_rssi_close_proximity = hal_req->config_5g_rssi_close_proximity; |
| ndev_vif->nan.config.rssi_close_5g_val = hal_req->rssi_close_5g_val; |
| ndev_vif->nan.config.rssi_middle_5g_val = hal_req->rssi_middle_5g_val; |
| ndev_vif->nan.config.rssi_close_proximity_5g_val = hal_req->rssi_close_proximity_5g_val; |
| ndev_vif->nan.config.scan_params_val.dwell_time[1] = hal_req->scan_params_val.dwell_time[1]; |
| ndev_vif->nan.config.scan_params_val.scan_period[1] = hal_req->scan_params_val.scan_period[1]; |
| ndev_vif->nan.config.config_5g_dw_band = (u16)hal_req->config_5g_dw_band; |
| ndev_vif->nan.config.dw_5g_interval_val = hal_req->dw_5g_interval_val; |
| ndev_vif->nan.state = 1; |
| } |
| |
| int slsi_mlme_nan_enable(struct slsi_dev *sdev, struct net_device *dev, struct slsi_hal_nan_enable_req *hal_req) |
| { |
| struct netdev_vif *ndev_vif = netdev_priv(dev); |
| struct sk_buff *req; |
| struct sk_buff *cfm; |
| int r = 0; |
| u16 nan_oper_ctrl = 0; |
| |
| SLSI_NET_DBG3(dev, SLSI_MLME, "\n"); |
| |
| /* mbulk data length = 0x0f + 4 + 2 * (9 + 4) + 0x07 + 4 = 56*/ |
| req = fapi_alloc(mlme_nan_start_req, MLME_NAN_START_REQ, ndev_vif->ifnum, 56); |
| if (!req) { |
| SLSI_NET_ERR(dev, "fapi alloc failure\n"); |
| return -ENOMEM; |
| } |
| |
| fapi_set_u16(req, u.mlme_nan_start_req.nan_operation_control_flags, nan_oper_ctrl); |
| fapi_set_u32(req, u.mlme_nan_start_req.spare_1, hal_req->transaction_id); |
| |
| r = slsi_mlme_nan_enable_fapi_data(ndev_vif, req, hal_req, !ndev_vif->nan.disable_cluster_merge); |
| if (r) { |
| SLSI_NET_ERR(dev, "Failed to construct mbulkdata\n"); |
| kfree_skb(req); |
| return -EINVAL; |
| } |
| |
| cfm = slsi_mlme_req_cfm(sdev, dev, req, MLME_NAN_START_CFM); |
| if (!cfm) |
| return -EIO; |
| |
| if (fapi_get_u16(cfm, u.mlme_nan_start_cfm.result_code) != FAPI_RESULTCODE_SUCCESS) { |
| SLSI_NET_ERR(dev, "MLME_NAN_START_CFM(result:0x%04x) ERROR\n", |
| fapi_get_u16(cfm, u.mlme_nan_start_cfm.result_code)); |
| r = -EINVAL; |
| } |
| if (!r) |
| slsi_mlme_nan_store_config(ndev_vif, hal_req); |
| kfree_skb(cfm); |
| return r; |
| } |
| |
| static u32 slsi_mlme_nan_publish_fapi_data(struct sk_buff *req, struct slsi_hal_nan_publish_req *hal_req) |
| { |
| u32 ret; |
| |
| ret = slsi_mlme_nan_append_discovery_config(req, hal_req->publish_type, hal_req->tx_type, hal_req->ttl, |
| hal_req->period, hal_req->publish_count, hal_req->publish_match_indicator, |
| (u16)hal_req->rssi_threshold_flag, (u16)hal_req->sdea_params.ranging_state, |
| (u16)hal_req->sdea_params.config_nan_data_path); |
| if (ret) { |
| SLSI_WARN_NODEV("Error append disovery config TLV\n"); |
| return ret; |
| } |
| |
| if (hal_req->service_name_len) { |
| ret = slsi_mlme_nan_append_service_name(req, hal_req->service_name_len, hal_req->service_name); |
| if (ret) { |
| SLSI_WARN_NODEV("Error append servicename TLV\n"); |
| return ret; |
| } |
| } |
| |
| if (hal_req->service_specific_info_len) { |
| ret = slsi_mlme_nan_append_service_specific_info(req, hal_req->service_specific_info_len, |
| hal_req->service_specific_info); |
| if (ret) { |
| SLSI_WARN_NODEV("Error append servSpecInfo TLV\n"); |
| return ret; |
| } |
| } |
| |
| if (hal_req->sdea_service_specific_info_len) { |
| ret = slsi_mlme_nan_append_ext_service_specific_info(req, hal_req->sdea_service_specific_info_len, |
| hal_req->sdea_service_specific_info); |
| if (ret) { |
| SLSI_WARN_NODEV("Error append extServSpecInfo TLV\n"); |
| return ret; |
| } |
| } |
| |
| if (hal_req->rx_match_filter_len) { |
| ret = slsi_mlme_nan_append_rx_match_filter(req, hal_req->rx_match_filter_len, hal_req->rx_match_filter); |
| if (ret) { |
| SLSI_WARN_NODEV("Error append rx match filter TLV\n"); |
| return ret; |
| } |
| } |
| |
| if (hal_req->tx_match_filter_len) { |
| ret = slsi_mlme_nan_append_tx_match_filter(req, hal_req->tx_match_filter_len, hal_req->tx_match_filter); |
| if (ret) { |
| SLSI_WARN_NODEV("Error append tx match filter TLV\n"); |
| return ret; |
| } |
| } |
| |
| if (hal_req->sdea_params.config_nan_data_path) { |
| ret = slsi_mlme_nan_append_data_path_sec(req, &hal_req->sec_info); |
| if (ret) { |
| SLSI_WARN_NODEV("Error append datapath sec TLV\n"); |
| return ret; |
| } |
| } |
| if (hal_req->sdea_params.ranging_state) { |
| ret = slsi_mlme_nan_append_ranging(req, &hal_req->ranging_cfg); |
| if (ret) |
| SLSI_WARN_NODEV("Error append ranging config TLV\n"); |
| } |
| return ret; |
| } |
| |
| int slsi_mlme_nan_publish(struct slsi_dev *sdev, struct net_device *dev, struct slsi_hal_nan_publish_req *hal_req, |
| u16 publish_id) |
| { |
| struct netdev_vif *ndev_vif = netdev_priv(dev); |
| struct sk_buff *req; |
| struct sk_buff *cfm; |
| int r = 0; |
| u16 nan_sdf_flags = 0; |
| |
| SLSI_NET_DBG3(dev, SLSI_MLME, "\n"); |
| if (hal_req) { |
| /* discovery_config_tlv, datapath_sec_tlv, ranging_cfg_tlv */ |
| u16 length = 18 + 70 + 11; |
| |
| length += hal_req->service_name_len ? hal_req->service_name_len + 4 : 0; |
| length += hal_req->service_specific_info_len ? hal_req->service_specific_info_len + 4 : 0; |
| length += hal_req->rx_match_filter_len ? hal_req->rx_match_filter_len + 4 : 0; |
| length += hal_req->tx_match_filter_len ? hal_req->tx_match_filter_len + 4 : 0; |
| length += hal_req->sdea_service_specific_info_len ? hal_req->sdea_service_specific_info_len + 4 : 0; |
| |
| req = fapi_alloc(mlme_nan_publish_req, MLME_NAN_PUBLISH_REQ, ndev_vif->ifnum, length); |
| if (!req) { |
| SLSI_NET_ERR(dev, "fapi alloc failure\n"); |
| return -ENOMEM; |
| } |
| |
| /* Set/Enable corresponding bits to disable any indications |
| * that follow a publish. |
| * BIT0 - Disable publish termination indication. |
| * BIT1 - Disable match expired indication. |
| * BIT2 - Disable followUp indication received (OTA). |
| */ |
| if (hal_req->recv_indication_cfg & BIT(0)) |
| nan_sdf_flags |= FAPI_NANSDFCONTROL_PUBLISH_END_EVENT; |
| if (hal_req->recv_indication_cfg & BIT(1)) |
| nan_sdf_flags |= FAPI_NANSDFCONTROL_MATCH_EXPIRED_EVENT; |
| if (hal_req->recv_indication_cfg & BIT(2)) |
| nan_sdf_flags |= FAPI_NANSDFCONTROL_RECEIVED_FOLLOWUP_EVENT; |
| /* Store the SDF Flags */ |
| ndev_vif->nan.nan_sdf_flags[publish_id] = nan_sdf_flags; |
| } else { |
| req = fapi_alloc(mlme_nan_publish_req, MLME_NAN_PUBLISH_REQ, ndev_vif->ifnum, 0); |
| if (!req) { |
| SLSI_NET_ERR(dev, "fapi alloc failure\n"); |
| return -ENOMEM; |
| } |
| } |
| |
| fapi_set_u16(req, u.mlme_nan_publish_req.session_id, publish_id); |
| fapi_set_u16(req, u.mlme_nan_publish_req.nan_sdf_flags, 0); |
| |
| if (hal_req) { |
| fapi_set_u32(req, u.mlme_nan_publish_req.spare_1, hal_req->transaction_id); |
| r = slsi_mlme_nan_publish_fapi_data(req, hal_req); |
| if (r) { |
| SLSI_NET_ERR(dev, "Failed to construct mbulkdata\n"); |
| kfree_skb(req); |
| return -EINVAL; |
| } |
| } else { |
| fapi_set_u32(req, u.mlme_nan_publish_req.spare_1, 0); |
| } |
| |
| cfm = slsi_mlme_req_cfm(sdev, dev, req, MLME_NAN_PUBLISH_CFM); |
| if (!cfm) |
| return -EIO; |
| |
| if (fapi_get_u16(cfm, u.mlme_nan_publish_cfm.result_code) != FAPI_RESULTCODE_SUCCESS) { |
| SLSI_NET_ERR(dev, "MLME_NAN_PUBLISH_CFM(result:0x%04x) ERROR\n", |
| fapi_get_u16(cfm, u.mlme_nan_publish_cfm.result_code)); |
| r = -EINVAL; |
| } |
| |
| if (hal_req && !r) |
| ndev_vif->nan.service_id_map |= (u32)BIT(publish_id); |
| else |
| ndev_vif->nan.service_id_map &= (u32)~BIT(publish_id); |
| kfree_skb(cfm); |
| return r; |
| } |
| |
| static u32 slsi_mlme_nan_subscribe_fapi_data(struct sk_buff *req, struct slsi_hal_nan_subscribe_req *hal_req) |
| { |
| u32 ret; |
| |
| ret = slsi_mlme_nan_append_subscribe_specific(req, hal_req->service_response_filter, |
| hal_req->service_response_include, |
| hal_req->use_service_response_filter, |
| hal_req->ssi_required_for_match_indication); |
| if (ret) { |
| SLSI_WARN_NODEV("Error append subscribe specific TLV\n"); |
| return ret; |
| } |
| |
| ret = slsi_mlme_nan_append_discovery_config(req, hal_req->subscribe_type, |
| hal_req->subscribe_type ? 0 : 1, hal_req->ttl, |
| hal_req->period, hal_req->subscribe_count, hal_req->subscribe_match_indicator, |
| hal_req->rssi_threshold_flag, (u16)hal_req->sdea_params.ranging_state, |
| hal_req->sdea_params.config_nan_data_path); |
| if (ret) { |
| SLSI_WARN_NODEV("Error append discovery config TLV\n"); |
| return ret; |
| } |
| |
| if (hal_req->service_name_len) { |
| ret = slsi_mlme_nan_append_service_name(req, hal_req->service_name_len, hal_req->service_name); |
| if (ret) { |
| SLSI_WARN_NODEV("Error append service name TLV\n"); |
| return ret; |
| } |
| } |
| |
| if (hal_req->service_specific_info_len) { |
| ret = slsi_mlme_nan_append_service_specific_info(req, hal_req->service_specific_info_len, |
| hal_req->service_specific_info); |
| if (ret) { |
| SLSI_WARN_NODEV("Error append servSpecInfo TLV\n"); |
| return ret; |
| } |
| } |
| |
| if (hal_req->rx_match_filter_len) { |
| ret = slsi_mlme_nan_append_rx_match_filter(req, hal_req->rx_match_filter_len, hal_req->rx_match_filter); |
| if (ret) { |
| SLSI_WARN_NODEV("Error append rx match filter TLV\n"); |
| return ret; |
| } |
| } |
| |
| if (hal_req->tx_match_filter_len) { |
| ret = slsi_mlme_nan_append_tx_match_filter(req, hal_req->tx_match_filter_len, hal_req->tx_match_filter); |
| if (ret) { |
| SLSI_WARN_NODEV("Error append tx match filter TLV\n"); |
| return ret; |
| } |
| } |
| |
| if (hal_req->sdea_service_specific_info_len) { |
| ret = slsi_mlme_nan_append_ext_service_specific_info(req, hal_req->sdea_service_specific_info_len, |
| hal_req->sdea_service_specific_info); |
| if (ret) { |
| SLSI_WARN_NODEV("Error append extServSpecInfo TLV\n"); |
| return ret; |
| } |
| } |
| |
| if (hal_req->sdea_params.config_nan_data_path) { |
| ret = slsi_mlme_nan_append_data_path_sec(req, &hal_req->sec_info); |
| if (ret) { |
| SLSI_WARN_NODEV("Error append datapath sec TLV\n"); |
| return ret; |
| } |
| } |
| if (hal_req->sdea_params.ranging_state) { |
| ret = slsi_mlme_nan_append_ranging(req, &hal_req->ranging_cfg); |
| if (ret) { |
| SLSI_WARN_NODEV("Error append ranging config TLV\n"); |
| return ret; |
| } |
| } |
| |
| ret = slsi_mlme_nan_append_address_set(req, hal_req->num_intf_addr_present, (u8 *)hal_req->intf_addr); |
| if (ret) |
| SLSI_WARN_NODEV("Error append address set TLV\n"); |
| return ret; |
| } |
| |
| int slsi_mlme_nan_subscribe(struct slsi_dev *sdev, struct net_device *dev, struct slsi_hal_nan_subscribe_req *hal_req, |
| u16 subscribe_id) |
| { |
| struct netdev_vif *ndev_vif = netdev_priv(dev); |
| struct sk_buff *req; |
| struct sk_buff *cfm; |
| int r = 0; |
| u16 nan_sdf_flags = 0; |
| |
| SLSI_NET_DBG3(dev, SLSI_MLME, "\n"); |
| if (hal_req) { |
| /* subscribespecific + discovery + data_path sec + ranging */ |
| u16 length = 11 + 18 + 70 + 11; |
| |
| length += hal_req->service_name_len ? hal_req->service_name_len + 4 : 0; |
| length += hal_req->service_specific_info_len ? hal_req->service_specific_info_len + 4 : 0; |
| length += hal_req->rx_match_filter_len ? hal_req->rx_match_filter_len + 4 : 0; |
| length += hal_req->tx_match_filter_len ? hal_req->tx_match_filter_len + 4 : 0; |
| length += hal_req->sdea_service_specific_info_len ? hal_req->sdea_service_specific_info_len + 4 : 0; |
| length += hal_req->num_intf_addr_present ? hal_req->num_intf_addr_present * 6 + 4 : 0; |
| |
| req = fapi_alloc(mlme_nan_subscribe_req, MLME_NAN_SUBSCRIBE_REQ, ndev_vif->ifnum, length); |
| if (!req) { |
| SLSI_NET_ERR(dev, "fapi alloc failure\n"); |
| return -ENOMEM; |
| } |
| /* Set/Enable corresponding bits to disable |
| * indications that follow a subscribe. |
| * BIT0 - Disable subscribe termination indication. |
| * BIT1 - Disable match expired indication. |
| * BIT2 - Disable followUp indication received (OTA). |
| */ |
| if (hal_req->recv_indication_cfg & BIT(0)) |
| nan_sdf_flags |= FAPI_NANSDFCONTROL_SUBSCRIBE_END_EVENT; |
| if (hal_req->recv_indication_cfg & BIT(1)) |
| nan_sdf_flags |= FAPI_NANSDFCONTROL_MATCH_EXPIRED_EVENT; |
| if (hal_req->recv_indication_cfg & BIT(2)) |
| nan_sdf_flags |= FAPI_NANSDFCONTROL_RECEIVED_FOLLOWUP_EVENT; |
| ndev_vif->nan.nan_sdf_flags[subscribe_id] = nan_sdf_flags; |
| } else { |
| req = fapi_alloc(mlme_nan_subscribe_req, MLME_NAN_SUBSCRIBE_REQ, ndev_vif->ifnum, 0); |
| if (!req) { |
| SLSI_NET_ERR(dev, "fapi alloc failure\n"); |
| return -ENOMEM; |
| } |
| } |
| |
| fapi_set_u16(req, u.mlme_nan_subscribe_req.session_id, subscribe_id); |
| fapi_set_u16(req, u.mlme_nan_subscribe_req.nan_sdf_flags, 0); |
| if (hal_req) { |
| fapi_set_u32(req, u.mlme_nan_subscribe_req.spare_1, hal_req->transaction_id); |
| r = slsi_mlme_nan_subscribe_fapi_data(req, hal_req); |
| if (r) { |
| SLSI_NET_ERR(dev, "Failed to construct mbulkdata\n"); |
| kfree_skb(req); |
| return -EINVAL; |
| } |
| } else { |
| fapi_set_u32(req, u.mlme_nan_subscribe_req.spare_1, 0); |
| } |
| |
| cfm = slsi_mlme_req_cfm(sdev, dev, req, MLME_NAN_SUBSCRIBE_CFM); |
| if (!cfm) |
| return -EIO; |
| |
| if (fapi_get_u16(cfm, u.mlme_nan_subscribe_cfm.result_code) != FAPI_RESULTCODE_SUCCESS) { |
| SLSI_NET_ERR(dev, "MLME_NAN_SUBSCRIBE_CFM(res:0x%04x)\n", |
| fapi_get_u16(cfm, u.mlme_nan_subscribe_cfm.result_code)); |
| r = -EINVAL; |
| } |
| |
| if (hal_req && !r) |
| ndev_vif->nan.service_id_map |= (u32)BIT(subscribe_id); |
| else |
| ndev_vif->nan.service_id_map &= (u32)~BIT(subscribe_id); |
| kfree_skb(cfm); |
| return r; |
| } |
| |
| static u32 slsi_mlme_nan_followup_fapi_data(struct sk_buff *req, struct slsi_hal_nan_transmit_followup_req *hal_req) |
| { |
| u32 ret; |
| |
| ret = slsi_mlme_nan_append_service_specific_info(req, hal_req->service_specific_info_len, |
| hal_req->service_specific_info); |
| if (ret) { |
| SLSI_WARN_NODEV("Error append service specific info TLV\n"); |
| return ret; |
| } |
| |
| ret = slsi_mlme_nan_append_ext_service_specific_info(req, hal_req->sdea_service_specific_info_len, |
| hal_req->sdea_service_specific_info); |
| if (ret) |
| SLSI_WARN_NODEV("Error append extServSpecInfo TLV\n"); |
| return ret; |
| } |
| |
| int slsi_mlme_nan_tx_followup(struct slsi_dev *sdev, struct net_device *dev, |
| struct slsi_hal_nan_transmit_followup_req *hal_req) |
| { |
| struct netdev_vif *ndev_vif = netdev_priv(dev); |
| struct sk_buff *req; |
| struct sk_buff *cfm; |
| int r = 0; |
| u16 nan_sdf_flags = 0; |
| u16 data_len; |
| |
| SLSI_NET_DBG3(dev, SLSI_MLME, "\n"); |
| |
| if (slsi_nan_push_followup_ids(sdev, dev, hal_req->requestor_instance_id, hal_req->transaction_id) < 0) { |
| SLSI_WARN(sdev, "Host followup_req queue full\n"); |
| return SLSI_HAL_NAN_STATUS_FOLLOWUP_QUEUE_FULL; |
| } |
| |
| data_len = hal_req->service_specific_info_len ? (hal_req->service_specific_info_len + 4) : 0; |
| data_len = hal_req->sdea_service_specific_info_len ? (hal_req->sdea_service_specific_info_len + 4) : 0; |
| |
| /* max possible length for publish attributes: 5*255 */ |
| req = fapi_alloc(mlme_nan_followup_req, MLME_NAN_FOLLOWUP_REQ, ndev_vif->ifnum, 5 * 255); |
| if (!req) { |
| SLSI_NET_ERR(dev, "fapi alloc failure\n"); |
| return -ENOMEM; |
| } |
| |
| fapi_set_u16(req, u.mlme_nan_followup_req.session_id, hal_req->publish_subscribe_id); |
| fapi_set_u16(req, u.mlme_nan_followup_req.match_id, hal_req->requestor_instance_id); |
| fapi_set_u16(req, u.mlme_nan_followup_req.nan_sdf_flags, nan_sdf_flags); |
| fapi_set_u32(req, u.mlme_nan_followup_req.spare_1, hal_req->transaction_id); |
| |
| r = slsi_mlme_nan_followup_fapi_data(req, hal_req); |
| if (r) { |
| SLSI_NET_ERR(dev, "Failed to construct mbulkdata\n"); |
| kfree_skb(req); |
| return -EINVAL; |
| } |
| |
| cfm = slsi_mlme_req_cfm(sdev, dev, req, MLME_NAN_FOLLOWUP_CFM); |
| if (!cfm) { |
| slsi_nan_pop_followup_ids(sdev, dev, hal_req->requestor_instance_id); |
| return -EIO; |
| } |
| |
| if (fapi_get_u16(cfm, u.mlme_nan_followup_cfm.result_code) != FAPI_RESULTCODE_SUCCESS) { |
| slsi_nan_pop_followup_ids(sdev, dev, hal_req->requestor_instance_id); |
| SLSI_NET_ERR(dev, "MLME_NAN_FOLLOWUP_CFM(res:0x%04x)\n", |
| fapi_get_u16(cfm, u.mlme_nan_followup_cfm.result_code)); |
| if (fapi_get_u16(cfm, u.mlme_nan_followup_cfm.result_code) == |
| FAPI_RESULTCODE_TOO_MANY_SIMULTANEOUS_REQUESTS) |
| r = SLSI_HAL_NAN_STATUS_FOLLOWUP_QUEUE_FULL; |
| else |
| r = -EINVAL; |
| } |
| |
| kfree_skb(cfm); |
| return r; |
| } |
| |
| static u32 slsi_mlme_nan_config_fapi_data(struct netdev_vif *ndev_vif, struct sk_buff *req, struct slsi_hal_nan_config_req *hal_req, u8 cluster_merge) |
| { |
| u16 rssi_window = hal_req->config_rssi_window_size ? hal_req->rssi_window_size_val : 8; |
| u32 ret; |
| u8 rssi_close = hal_req->rssi_close_2dot4g_val; |
| u8 rssi_middle = hal_req->rssi_middle_2dot4g_val; |
| u8 rssi_proximity = 0; |
| |
| u16 is_sid_in_beacon = hal_req->config_subscribe_sid_beacon && (hal_req->subscribe_sid_beacon_val & 0x01); |
| u8 sid_count_in_beacon = hal_req->config_subscribe_sid_beacon ? hal_req->subscribe_sid_beacon_val >> 1 : 0; |
| |
| if (!hal_req->master_pref) |
| hal_req->master_pref = ndev_vif->nan.master_pref_value; |
| |
| ret = slsi_mlme_nan_append_config_tlv(req, hal_req->master_pref, |
| hal_req->config_sid_beacon && (hal_req->sid_beacon & 0x01), |
| hal_req->config_sid_beacon ? hal_req->sid_beacon >> 1 : 0, |
| is_sid_in_beacon, sid_count_in_beacon, rssi_window, |
| hal_req->disc_mac_addr_rand_interval_sec, cluster_merge); |
| if (ret) { |
| SLSI_WARN_NODEV("Error append config TLV\n"); |
| return ret; |
| } |
| |
| /* 2.4G NAN band specific config*/ |
| rssi_proximity = hal_req->config_rssi_proximity ? hal_req->rssi_proximity : 0; |
| |
| ret = slsi_mlme_nan_append_2g4_band_specific_config(req, rssi_close, rssi_middle, rssi_proximity, |
| hal_req->scan_params_val.dwell_time[0], |
| hal_req->scan_params_val.scan_period[0], |
| hal_req->config_2dot4g_dw_band, |
| hal_req->dw_2dot4g_interval_val); |
| if (ret) { |
| SLSI_WARN_NODEV("Error append 2.4G band specific TLV\n"); |
| return ret; |
| } |
| |
| /* 5G NAN band specific config*/ |
| rssi_close = hal_req->rssi_close_5g_val; |
| rssi_middle = hal_req->rssi_middle_5g_val; |
| rssi_proximity = hal_req->config_5g_rssi_close_proximity ? hal_req->rssi_close_proximity_5g_val : 0; |
| |
| ret = slsi_mlme_nan_append_5g_band_specific_config(req, rssi_close, rssi_middle, rssi_proximity, |
| hal_req->scan_params_val.dwell_time[1], |
| hal_req->scan_params_val.scan_period[1], |
| hal_req->config_5g_dw_band, |
| hal_req->dw_5g_interval_val); |
| if (ret) { |
| SLSI_WARN_NODEV("Error append 5G band specific TLV\n"); |
| return ret; |
| } |
| |
| ret = slsi_mlme_nan_append_config_supplemental(req, hal_req->discovery_beacon_interval_ms, |
| hal_req->nss_discovery, hal_req->enable_dw_early_termination, |
| hal_req->enable_ranging); |
| if (ret) { |
| SLSI_WARN_NODEV("Failed to add config supplemental TLV\n"); |
| return ret; |
| } |
| return ret; |
| } |
| |
| int slsi_mlme_nan_set_config(struct slsi_dev *sdev, struct net_device *dev, struct slsi_hal_nan_config_req *hal_req) |
| { |
| struct netdev_vif *ndev_vif = netdev_priv(dev); |
| struct sk_buff *req; |
| struct sk_buff *cfm; |
| int r = 0; |
| u16 nan_oper_ctrl = 0; |
| |
| SLSI_NET_DBG3(dev, SLSI_MLME, "\n"); |
| /* mbulk data length = 0x0f + 4 + 2 * (9 + 4) + 0x07 + 4 = 56 */ |
| req = fapi_alloc(mlme_nan_config_req, MLME_NAN_CONFIG_REQ, ndev_vif->ifnum, 56); |
| if (!req) { |
| SLSI_NET_ERR(dev, "fapi alloc failure\n"); |
| return -ENOMEM; |
| } |
| |
| fapi_set_u16(req, u.mlme_nan_config_req.nan_operation_control_flags, nan_oper_ctrl); |
| fapi_set_u32(req, u.mlme_nan_config_req.spare_1, hal_req->transaction_id); |
| |
| r = slsi_mlme_nan_config_fapi_data(ndev_vif, req, hal_req, !ndev_vif->nan.disable_cluster_merge); |
| if (r) { |
| SLSI_NET_ERR(dev, "Failed to construct mbulkdata\n"); |
| kfree_skb(req); |
| return -EINVAL; |
| } |
| |
| cfm = slsi_mlme_req_cfm(sdev, dev, req, MLME_NAN_CONFIG_CFM); |
| if (!cfm) |
| return -EIO; |
| |
| if (fapi_get_u16(cfm, u.mlme_nan_config_cfm.result_code) != FAPI_RESULTCODE_SUCCESS) { |
| SLSI_NET_ERR(dev, "MLME_NAN_FOLLOWUP_CFM(res:0x%04x)\n", |
| fapi_get_u16(cfm, u.mlme_nan_config_cfm.result_code)); |
| r = -EINVAL; |
| } |
| |
| kfree_skb(cfm); |
| return r; |
| } |
| |
| static int slsi_mlme_ndp_request_fapi_data(struct sk_buff *req, |
| struct slsi_hal_nan_data_path_initiator_req *hal_req, |
| bool include_ipv6_addr_tlv, bool include_service_info_tlv, |
| u8 *local_ndi) |
| { |
| int ret; |
| |
| ret = slsi_mlme_nan_append_data_path_sec(req, &hal_req->key_info); |
| if (ret) { |
| SLSI_WARN_NODEV("Error data_path sec TLV\n"); |
| return ret; |
| } |
| |
| if (hal_req->app_info.ndp_app_info_len) { |
| ret = slsi_mlme_nan_append_tlv(req, SLSI_NAN_TLV_TAG_APP_INFO, hal_req->app_info.ndp_app_info_len, |
| hal_req->app_info.ndp_app_info); |
| if (ret) { |
| SLSI_WARN_NODEV("Error app info TLV\n"); |
| return ret; |
| } |
| } |
| if (include_service_info_tlv) { |
| ret = slsi_mlme_nan_append_service_info_tlv(req, &hal_req->app_info); |
| if (ret) |
| SLSI_WARN_NODEV("Error Adding Service Info TLV\n"); |
| } |
| if (include_ipv6_addr_tlv) { |
| ret = slsi_mlme_nan_append_ipv6_link_tlv(req, local_ndi); |
| if (ret) |
| SLSI_WARN_NODEV("Error ipv6 link tlv\n"); |
| } |
| if (hal_req->service_name_len) { |
| ret = slsi_mlme_nan_append_service_name(req, hal_req->service_name_len, hal_req->service_name); |
| if (ret) |
| SLSI_WARN_NODEV("Error append servicename TLV\n"); |
| } |
| return ret; |
| } |
| |
| int slsi_mlme_ndp_request(struct slsi_dev *sdev, struct net_device *dev, |
| struct slsi_hal_nan_data_path_initiator_req *hal_req, u32 ndp_instance_id, u16 ndl_vif_id) |
| { |
| struct netdev_vif *ndev_vif = netdev_priv(dev); |
| struct sk_buff *req; |
| struct sk_buff *cfm; |
| int r = 0, data_len; |
| bool include_ipv6_link_tlv, include_service_info_tlv = 0; |
| u8 *local_ndi; |
| struct net_device *data_dev; |
| struct netdev_vif *ndev_data_vif; |
| |
| SLSI_NET_DBG3(dev, SLSI_MLME, "\n"); |
| |
| data_dev = slsi_get_netdev_by_ifname(sdev, hal_req->ndp_iface); |
| if (!data_dev) { |
| SLSI_NET_ERR(dev, "no net_device for %s\n", hal_req->ndp_iface); |
| return -EINVAL; |
| } |
| local_ndi = data_dev->dev_addr; |
| ndev_data_vif = netdev_priv(data_dev); |
| |
| include_ipv6_link_tlv = slsi_dev_nan_is_ipv6_link_tlv_include(); |
| |
| data_len = 74; /* for datapath security tlv */ |
| data_len += hal_req->app_info.ndp_app_info_len ? 4 + hal_req->app_info.ndp_app_info_len : 0; |
| data_len += include_ipv6_link_tlv ? 4 + 8 : 0; |
| data_len += hal_req->service_name_len ? hal_req->service_name_len + 4 : 0; |
| if (hal_req->app_info.ndp_app_info_len) { |
| u16 length; |
| |
| length = slsi_mlme_nan_service_info_tlv_length(&hal_req->app_info); |
| data_len += (length + 1); |
| include_service_info_tlv = 1; |
| } |
| req = fapi_alloc(mlme_ndp_request_req, MLME_NDP_REQUEST_REQ, ndev_vif->ifnum, data_len); |
| if (!req) { |
| SLSI_NET_ERR(dev, "fapi alloc failure\n"); |
| return -ENOMEM; |
| } |
| |
| fapi_set_u16(req, u.mlme_ndp_request_req.ndl_vif_index, ndl_vif_id); |
| fapi_set_u16(req, u.mlme_ndp_request_req.match_id, hal_req->requestor_instance_id); |
| fapi_set_memcpy(req, u.mlme_ndp_request_req.local_ndp_interface_address, local_ndi); |
| fapi_set_memcpy(req, u.mlme_ndp_request_req.peer_nmi, hal_req->peer_disc_mac_addr); |
| fapi_set_u16(req, u.mlme_ndp_request_req.ndp_instance_id, ndp_instance_id); |
| fapi_set_u32(req, u.mlme_ndp_request_req.spare_1, hal_req->transaction_id); |
| |
| r = slsi_mlme_ndp_request_fapi_data(req, hal_req, include_ipv6_link_tlv, include_service_info_tlv, local_ndi); |
| if (r) { |
| SLSI_NET_ERR(dev, "Failed to construct mbulkdata\n"); |
| kfree_skb(req); |
| return -EINVAL; |
| } |
| |
| cfm = slsi_mlme_req_cfm(sdev, dev, req, MLME_NDP_REQUEST_CFM); |
| if (!cfm) |
| return -EIO; |
| |
| if (fapi_get_u16(cfm, u.mlme_ndp_request_cfm.result_code) != FAPI_RESULTCODE_SUCCESS) { |
| SLSI_NET_ERR(dev, "MLME_NDP_REQUEST_CFM(res:0x%04x)\n", |
| fapi_get_u16(cfm, u.mlme_ndp_request_cfm.result_code)); |
| r = -EINVAL; |
| } else { |
| SLSI_MUTEX_LOCK(ndev_data_vif->vif_mutex); |
| ndev_data_vif->nan.ndp_count++; |
| SLSI_MUTEX_UNLOCK(ndev_data_vif->vif_mutex); |
| if (slsi_nan_ndp_new_entry(sdev, dev, ndp_instance_id, ndl_vif_id, local_ndi, hal_req->peer_disc_mac_addr)) |
| SLSI_NET_ERR(dev, "invalid ndl_vifid:%d ndp_id:%d\n", ndl_vif_id, ndp_instance_id); |
| } |
| |
| kfree_skb(cfm); |
| return r; |
| } |
| |
| static int slsi_mlme_ndp_response_fapi_data(struct sk_buff *req, |
| struct slsi_hal_nan_data_path_indication_response *hal_req, |
| bool include_ipv6_link_tlv, bool include_service_info_tlv, |
| u8 *local_ndi) |
| { |
| int ret; |
| |
| ret = slsi_mlme_nan_append_data_path_sec(req, &hal_req->key_info); |
| if (ret) { |
| SLSI_WARN_NODEV("Error data_path sec TLV\n"); |
| return ret; |
| } |
| |
| if (hal_req->app_info.ndp_app_info_len) { |
| ret = slsi_mlme_nan_append_tlv(req, SLSI_NAN_TLV_TAG_APP_INFO, hal_req->app_info.ndp_app_info_len, |
| hal_req->app_info.ndp_app_info); |
| if (ret) { |
| SLSI_WARN_NODEV("Error app info TLV\n"); |
| return ret; |
| } |
| } |
| if (include_service_info_tlv) { |
| ret = slsi_mlme_nan_append_service_info_tlv(req, &hal_req->app_info); |
| if (ret) |
| SLSI_WARN_NODEV("Error Adding Service Info TLV\n"); |
| } |
| if (include_ipv6_link_tlv) { |
| ret = slsi_mlme_nan_append_ipv6_link_tlv(req, local_ndi); |
| if (ret) |
| SLSI_WARN_NODEV("Error ipv6 link tlv\n"); |
| } |
| if (hal_req->service_name_len) { |
| ret = slsi_mlme_nan_append_service_name(req, hal_req->service_name_len, hal_req->service_name); |
| if (ret) |
| SLSI_WARN_NODEV("Error append servicename TLV\n"); |
| } |
| return ret; |
| } |
| |
| int slsi_mlme_ndp_response(struct slsi_dev *sdev, struct net_device *dev, |
| struct slsi_hal_nan_data_path_indication_response *hal_req, u16 local_ndp_instance_id) |
| { |
| struct netdev_vif *ndev_vif = netdev_priv(dev); |
| struct sk_buff *req; |
| struct sk_buff *cfm; |
| int r = 0, data_len; |
| bool include_ipv6_link_tlv, include_service_info_tlv = 0; |
| u8 *local_ndi; |
| u16 ndl_vif_id, rsp_code; |
| struct net_device *data_dev; |
| u8 nomac[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; |
| |
| SLSI_NET_DBG3(dev, SLSI_MLME, "\n"); |
| data_dev = slsi_get_netdev_by_ifname(sdev, hal_req->ndp_iface); |
| if (!data_dev) |
| local_ndi = nomac; |
| else |
| local_ndi = data_dev->dev_addr; |
| |
| include_ipv6_link_tlv = slsi_dev_nan_is_ipv6_link_tlv_include(); |
| |
| data_len = 74; /* for datapath security tlv */ |
| data_len += hal_req->app_info.ndp_app_info_len ? 4 + hal_req->app_info.ndp_app_info_len : 0; |
| data_len += include_ipv6_link_tlv ? 4 + 8 : 0; |
| data_len += hal_req->service_name_len ? 4 + hal_req->service_name_len : 0; |
| if (hal_req->app_info.ndp_app_info_len) { |
| u16 length; |
| |
| length = slsi_mlme_nan_service_info_tlv_length(&hal_req->app_info); |
| data_len += (length + 1); |
| include_service_info_tlv = 1; |
| } |
| |
| req = fapi_alloc(mlme_ndp_response_req, MLME_NDP_RESPONSE_REQ, ndev_vif->ifnum, data_len); |
| if (!req) { |
| SLSI_NET_ERR(dev, "fapi alloc failure\n"); |
| return -ENOMEM; |
| } |
| if (hal_req->ndp_instance_id) |
| ndl_vif_id = ndev_vif->nan.ndp_instance_id2ndl_vif[hal_req->ndp_instance_id - 1]; |
| else |
| ndl_vif_id = 0; |
| fapi_set_u16(req, u.mlme_ndp_response_req.ndl_vif_index, ndl_vif_id); |
| fapi_set_u16(req, u.mlme_ndp_response_req.request_id, local_ndp_instance_id); |
| fapi_set_memcpy(req, u.mlme_ndp_response_req.local_ndp_interface_address, local_ndi); |
| fapi_set_u16(req, u.mlme_ndp_response_req.ndp_instance_id, hal_req->ndp_instance_id); |
| fapi_set_u32(req, u.mlme_ndp_response_req.spare_1, hal_req->transaction_id); |
| |
| rsp_code = hal_req->rsp_code == NAN_DP_REQUEST_ACCEPT ? FAPI_REASONCODE_NDP_ACCEPTED : |
| FAPI_REASONCODE_NDP_REJECTED; |
| fapi_set_u16(req, u.mlme_ndp_response_req.reason_code, rsp_code); |
| r = slsi_mlme_ndp_response_fapi_data(req, hal_req, include_ipv6_link_tlv, include_service_info_tlv, local_ndi); |
| if (r) { |
| SLSI_NET_ERR(dev, "Failed to construct mbulkdata\n"); |
| kfree_skb(req); |
| return -EINVAL; |
| } |
| |
| cfm = slsi_mlme_req_cfm(sdev, dev, req, MLME_NDP_RESPONSE_CFM); |
| if (!cfm) |
| return -EIO; |
| |
| if (fapi_get_u16(cfm, u.mlme_ndp_response_cfm.result_code) != FAPI_RESULTCODE_SUCCESS) { |
| SLSI_NET_ERR(dev, "MLME_NDP_RESPONSE_CFM(res:0x%04x)\n", |
| fapi_get_u16(cfm, u.mlme_ndp_request_cfm.result_code)); |
| r = -EINVAL; |
| slsi_nan_ndp_del_entry(sdev, dev, hal_req->ndp_instance_id, false); |
| } else { |
| if (rsp_code == FAPI_REASONCODE_NDP_REJECTED) |
| slsi_nan_ndp_del_entry(sdev, dev, hal_req->ndp_instance_id, false); |
| /* new ndp entry was made when received mlme-ndp-requested.ind |
| * but local_ndi is decided now. |
| */ |
| if (hal_req->ndp_instance_id && rsp_code == FAPI_REASONCODE_NDP_ACCEPTED) |
| ether_addr_copy(ndev_vif->nan.ndp_ndi[hal_req->ndp_instance_id - 1], local_ndi); |
| if (data_dev) { |
| struct netdev_vif *ndev_data_vif = netdev_priv(data_dev); |
| |
| ndev_data_vif = netdev_priv(data_dev); |
| SLSI_MUTEX_LOCK(ndev_data_vif->vif_mutex); |
| ndev_data_vif->nan.ndp_count++; |
| SLSI_MUTEX_UNLOCK(ndev_data_vif->vif_mutex); |
| } |
| } |
| |
| kfree_skb(cfm); |
| return r; |
| } |
| |
| int slsi_mlme_ndp_terminate(struct slsi_dev *sdev, struct net_device *dev, u16 ndp_instance_id, u16 transaction_id) |
| { |
| struct netdev_vif *ndev_vif = netdev_priv(dev); |
| struct sk_buff *req; |
| struct sk_buff *cfm; |
| |
| if (ndev_vif->nan.ndp_state[ndp_instance_id - 1] != ndp_slot_status_in_use) { |
| slsi_nan_ndp_termination_handler(sdev, dev, ndp_instance_id, ndev_vif->nan.ndp_ndi[ndp_instance_id - 1]); |
| return 0; |
| } |
| |
| req = fapi_alloc(mlme_ndp_terminate_req, MLME_NDP_TERMINATE_REQ, ndev_vif->ifnum, 0); |
| if (!req) { |
| SLSI_NET_ERR(dev, "fapi alloc failure\n"); |
| return -ENOMEM; |
| } |
| |
| fapi_set_u16(req, u.mlme_ndp_terminate_req.ndp_instance_id, ndp_instance_id); |
| fapi_set_u32(req, u.mlme_ndp_terminate_req.spare_1, transaction_id); |
| cfm = slsi_mlme_req_cfm(sdev, dev, req, MLME_NDP_TERMINATE_CFM); |
| if (!cfm) { |
| slsi_nan_ndp_termination_handler(sdev, dev, ndp_instance_id, ndev_vif->nan.ndp_ndi[ndp_instance_id - 1]); |
| return -EIO; |
| } |
| |
| if (fapi_get_u16(cfm, u.mlme_ndp_terminate_cfm.result_code) != FAPI_RESULTCODE_SUCCESS) { |
| SLSI_NET_ERR(dev, "MLME_NDP_TERMINATE_CFM(res:0x%04x)\n", |
| fapi_get_u16(cfm, u.mlme_ndp_terminate_cfm.result_code)); |
| slsi_nan_ndp_termination_handler(sdev, dev, ndp_instance_id, ndev_vif->nan.ndp_ndi[ndp_instance_id - 1]); |
| } |
| |
| kfree_skb(cfm); |
| return 0; |
| } |
| |
| int slsi_mlme_nan_range_req(struct slsi_dev *sdev, struct net_device *dev, u8 count, |
| struct slsi_rtt_config *nl_rtt_params) |
| { |
| struct sk_buff *req; |
| struct sk_buff *rx; |
| struct netdev_vif *ndev_vif = netdev_priv(dev); |
| int r = 0, i; |
| |
| WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); |
| req = fapi_alloc(mlme_nan_range_req, MLME_NAN_RANGE_REQ, 0, count * (SLSI_NAN_TLV_NAN_RTT_CONFIG_LEN + 4)); |
| if (!req) { |
| SLSI_ERR(sdev, "failed to alloc %zd\n", count * (SLSI_NAN_TLV_NAN_RTT_CONFIG_LEN + 4)); |
| return -ENOMEM; |
| } |
| SLSI_DBG2(sdev, SLSI_MLME, "count:%d\n", count); |
| /*fill the data */ |
| fapi_set_u16(req, u.mlme_nan_range_req.vif, ndev_vif->ifnum); |
| for (i = 0; i < count; i++) { |
| fapi_append_data_u16(req, SLSI_NAN_TLV_NAN_RTT_CONFIG); |
| fapi_append_data_u16(req, SLSI_NAN_TLV_NAN_RTT_CONFIG_LEN); |
| fapi_append_data(req, nl_rtt_params[i].peer_addr, ETH_ALEN); |
| fapi_append_data_u8(req, nl_rtt_params[i].num_frames_per_burst); |
| fapi_append_data_u8(req, nl_rtt_params[i].burst_duration); |
| fapi_append_data_u8(req, nl_rtt_params[i].num_retries_per_ftmr); |
| } |
| rx = slsi_mlme_req_cfm(sdev, dev, req, MLME_NAN_RANGE_CFM); |
| if (!rx) |
| return -EIO; |
| if (fapi_get_u16(rx, u.mlme_nan_range_cfm.result_code) != FAPI_RESULTCODE_SUCCESS) { |
| SLSI_ERR(sdev, "mlme_nan_range_cfm(ERROR:0x%04x)", |
| fapi_get_u16(rx, u.mlme_nan_range_cfm.result_code)); |
| r = -EINVAL; |
| } |
| |
| kfree_skb(rx); |
| return r; |
| } |
| |
| static bool slsi_nan_range_cancel_cfm_validate(struct slsi_dev *sdev, struct net_device *dev, struct sk_buff *cfm) |
| { |
| int result = fapi_get_u16(cfm, u.mlme_nan_range_cancel_cfm.result_code); |
| bool r = false; |
| |
| SLSI_UNUSED_PARAMETER(sdev); |
| |
| if (WARN_ON(!dev)) |
| goto exit; |
| |
| if (result == FAPI_RESULTCODE_SUCCESS) |
| r = true; |
| else |
| SLSI_NET_ERR(dev, "mlme_nan_range_cancel_cfm(result:0x%04x) ERROR\n", result); |
| |
| exit: |
| kfree_skb(cfm); |
| return r; |
| } |
| |
| int slsi_mlme_nan_range_cancel_req(struct slsi_dev *sdev, struct net_device *dev) |
| { |
| struct sk_buff *req; |
| struct sk_buff *rx; |
| struct netdev_vif *ndev_vif = netdev_priv(dev); |
| int r = 0; |
| |
| WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex)); |
| /* Alloc data size */ |
| req = fapi_alloc(mlme_nan_range_cancel_req, MLME_NAN_RANGE_CANCEL_REQ, 0, 0); |
| if (!req) { |
| SLSI_ERR(sdev, "failed to alloc cancel req\n"); |
| return -ENOMEM; |
| } |
| /*fill the data */ |
| fapi_set_u16(req, u.mlme_nan_range_cancel_req.vif, ndev_vif->ifnum); |
| |
| rx = slsi_mlme_req_cfm_ind(sdev, dev, req, MLME_NAN_RANGE_CANCEL_CFM, MLME_SPARE_5_IND, slsi_nan_range_cancel_cfm_validate); |
| if (!rx) { |
| SLSI_NET_ERR(dev, "mlme_nan_range_cancel_cfm() ERROR\n"); |
| r = -EINVAL; |
| } |
| kfree_skb(rx); |
| return r; |
| } |
| |