/****************************************************************************** * * Copyright(c) 2007 - 2019 Realtek Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * *****************************************************************************/ #include #include #include #if defined(CONFIG_ALIBABA_ZEROCONFIG) #define GENL_CUSTOM_FAMILY_NAME "WIFI_NL_CUSTOM" #define MAX_CUSTOM_PKT_LENGTH 2048 #ifndef CONFIG_APPEND_VENDOR_IE_ENABLE #define WLAN_MAX_VENDOR_IE_LEN 255 #endif enum { __GENL_CUSTOM_ATTR_INVALID, GENL_CUSTOM_ATTR_MSG, /* message */ __GENL_CUSTOM_ATTR_MAX, }; #define GENL_CUSTOM_ATTR_MAX (__GENL_CUSTOM_ATTR_MAX - 1) enum { __GENLL_CUSTOM_COMMAND_INVALID, GENL_CUSTOM_COMMAND_BIND, /* bind */ GENL_CUSTOM_COMMAND_SEND, /* user -> kernel */ GENL_CUSTOM_COMMAND_RECV, /* kernel -> user */ __GENL_CUSTOM_COMMAND_MAX, }; #define GENL_CUSTOM_COMMAND_MAX (__GENL_CUSTOM_COMMAND_MAX - 1) static int rtw_genl_bind(struct sk_buff *skb, struct genl_info *info); static int rtw_genl_recv(struct sk_buff *skb, struct genl_info *info); #define GENLMSG_UNICAST_RETRY_LIMIT 5 static int rtw_genl_send_retry_cnt = 0; static struct genl_family rtw_genl_family = { .id = GENL_ID_GENERATE, .hdrsize = 0, .name = GENL_CUSTOM_FAMILY_NAME, .version = 1, .maxattr = GENL_CUSTOM_ATTR_MAX, }; static struct nla_policy rtw_genl_policy[GENL_CUSTOM_ATTR_MAX + 1] = { [GENL_CUSTOM_ATTR_MSG] = {.type = NLA_NUL_STRING}, }; static struct genl_ops rtw_genl_ops[] = { { .cmd = GENL_CUSTOM_COMMAND_BIND, .flags = 0, .policy = rtw_genl_policy, .doit = rtw_genl_bind, .dumpit = NULL, }, { .cmd = GENL_CUSTOM_COMMAND_SEND, .flags = 0, .policy = rtw_genl_policy, .doit = rtw_genl_recv, .dumpit = NULL, }, }; static _adapter *padapter_for_genl = NULL; void rtw_genl_init(_adapter *padapter) { if (genl_register_family_with_ops(&rtw_genl_family, rtw_genl_ops) != 0){ RTW_INFO("%s(): GE_NELINK family registration fail\n", __func__); } else { padapter_for_genl = padapter; padapter_for_genl->genl_bind_pid = -1; _rtw_memset(padapter_for_genl->target_macaddr, 0, ETH_ALEN); } } void rtw_genl_deinit(void) { genl_unregister_family(&rtw_genl_family); if(padapter_for_genl != NULL) { padapter_for_genl->genl_bind_pid = -1; _rtw_memset(padapter_for_genl->target_macaddr, 0, ETH_ALEN); padapter_for_genl = NULL; } } static int rtw_genl_bind(struct sk_buff *skb, struct genl_info *info) { struct nlattr *na; char* pData = NULL; int DataLen = 0; struct mlme_priv *pmlmepriv = &(padapter_for_genl->mlmepriv); RTW_INFO("%s : net_device name : %s\n",__func__, padapter_for_genl->pnetdev->name); if (info == NULL) { RTW_ERR("%s : genl_info is NULL\n", __func__); return -1; } na = info->attrs[GENL_CUSTOM_ATTR_MSG]; if (na) { pData = (char*) nla_data(na); DataLen = nla_len(na); #if defined(CONFIG_ALIBABA_ZEROCONFIG_DBG) RTW_INFO("%s nla_len(na) : %d\n", __func__, DataLen); RTW_INFO_DUMP(NULL, pData, DataLen); #endif } if (strcmp(pData, "BIND") == 0) { padapter_for_genl->genl_bind_pid = info->snd_portid; #if defined(CONFIG_ALIBABA_ZEROCONFIG_DBG) RTW_INFO("BIND\n"); RTW_INFO("%s : pid = %d\n", __func__, info->snd_portid); RTW_INFO("%s : padapter_for_genl->genl_bind_pid = %d\n", __func__, padapter_for_genl->genl_bind_pid); #endif #if defined(CONFIG_POWER_SAVING) RTW_INFO("%s : disable ips & lps\n", __func__); rtw_pm_set_lps(padapter_for_genl, PS_MODE_ACTIVE); rtw_pm_set_ips(padapter_for_genl, IPS_NONE); #endif } else if (strcmp(pData, "UNBIND") == 0) { #if defined(CONFIG_ALIBABA_ZEROCONFIG_DBG) RTW_INFO("UNBIND\n"); RTW_INFO("%s : pid = %d\n", __func__, info->snd_portid); RTW_INFO("%s : padapter_for_genl->genl_bind_pid = %d\n", __func__, padapter_for_genl->genl_bind_pid); #endif padapter_for_genl->genl_bind_pid = -1; _rtw_memset(padapter_for_genl->target_macaddr, 0, ETH_ALEN); #if defined(CONFIG_POWER_SAVING) RTW_INFO("%s() enable ips & lps\n", __func__); rtw_pm_set_lps(padapter_for_genl, PS_MODE_MAX); rtw_pm_set_ips(padapter_for_genl, IPS_NORMAL); #endif } else { RTW_INFO("%s(): Unknown cmd %s\n", __func__, pData); } return 0; } static int rtw_genl_send_probersp(char* buf, int buf_len){ struct mlme_priv *pmlmepriv = &(padapter_for_genl->mlmepriv); char da[6]; char* pVendorIE = NULL; int VendorIELength = 0; if(buf == NULL || buf_len <= 0){ RTW_ERR("%s buf is NULL or buf_len <= 0\n", __func__); return -1; } _rtw_memcpy(da, (buf + 4), MACADDRLEN); pVendorIE = rtw_get_ie((buf + 36), _VENDOR_SPECIFIC_IE_, &VendorIELength, buf_len - 36); // VendorIELength must include element id and length field VendorIELength += 2; if(VendorIELength > WLAN_MAX_VENDOR_IE_LEN) { RTW_ERR("VendorIELength exceeding 255\n"); RTW_INFO("%s dump vendor ie\n", __func__); RTW_INFO_DUMP(NULL, pVendorIE, VendorIELength); return -1; } #if defined(CONFIG_ALIBABA_ZEROCONFIG_DBG) RTW_INFO("%s da:"MAC_FMT"\n", __func__, MAC_ARG(da)); RTW_INFO("%s vendor ie length : %d \n", __func__, VendorIELength); RTW_INFO("%s dump vendor ie\n", __func__); RTW_INFO_DUMP(NULL, pVendorIE, VendorIELength); #endif //issue_probersp(padapter_for_genl, da, 0); issue_probersp_zeroconf(padapter_for_genl, buf, buf_len); return 0; } static int rtw_genl_recv(struct sk_buff *skb, struct genl_info *info) { struct nlattr *na; char* pData = NULL; int DataLen = 0; if (info == NULL) { RTW_ERR("%s : genl_info is NULL\n", __func__); return -1; } RTW_INFO("%s : recv from process %d\n", __func__, info->snd_portid); na = info->attrs[GENL_CUSTOM_ATTR_MSG]; if (na) { pData = (char*) nla_data(na); DataLen = nla_len(na); #if defined(CONFIG_ALIBABA_ZEROCONFIG_DBG) RTW_INFO("%s nla_len(na) : %d\n", __func__, DataLen); RTW_INFO_DUMP(NULL, pData, DataLen); #endif } if(*pData == 0x50) { RTW_INFO("%s : probe rsp\n", __func__); rtw_genl_send_probersp(pData, DataLen); } else if(*pData == 0x40) { RTW_ERR("%s : probe req\n", __func__); } else { RTW_ERR("%s : Unexpected pkt\n", __func__); RTW_INFO_DUMP(NULL, pData, DataLen); } return 0; } int rtw_genl_send(char* buf, int buf_len) { struct sk_buff *skb = NULL; char* msg_head = NULL; int ret = -1; if (padapter_for_genl->genl_bind_pid == -1) { RTW_ERR("%s : There is no binded process\n", __func__); return -1; } RTW_INFO("%s : send to process %d\n", __func__, padapter_for_genl->genl_bind_pid); if(buf == NULL || buf_len <= 0) { RTW_ERR("%s buf is NULL or buf_len : %d\n", __func__, buf_len); return -1; } #if defined(CONFIG_ALIBABA_ZEROCONFIG_DBG) RTW_INFO("%s dump buf\n", __func__); RTW_INFO_DUMP(NULL, buf, buf_len); #endif skb = genlmsg_new(MAX_CUSTOM_PKT_LENGTH, GFP_KERNEL); if (skb) { msg_head = genlmsg_put(skb, 0, 0, &rtw_genl_family, 0, GENL_CUSTOM_COMMAND_RECV); if (msg_head == NULL) { nlmsg_free(skb); RTW_ERR("%s(): genlmsg_put fail\n", __func__); return -1; } ret = nla_put(skb, GENL_CUSTOM_ATTR_MSG, buf_len, buf); if (ret != 0) { nlmsg_free(skb); RTW_INFO("%s(): nla_put fail : %d\n", __func__, ret); return ret; } genlmsg_end(skb, msg_head); /* sending message */ ret = genlmsg_unicast(&init_net, skb, padapter_for_genl->genl_bind_pid); if (ret != 0) { RTW_ERR("%s(): genlmsg_unicast fail : %d\n", __func__, ret); rtw_genl_send_retry_cnt++; if(rtw_genl_send_retry_cnt >= GENLMSG_UNICAST_RETRY_LIMIT){ RTW_ERR("%s(): Exceeding retry cnt %d, process might be killed\n", __func__, rtw_genl_send_retry_cnt); RTW_ERR("%s(): Unbind pid : %d\n", __func__, padapter_for_genl->genl_bind_pid); padapter_for_genl->genl_bind_pid = -1; _rtw_memset(padapter_for_genl->target_macaddr, 0, ETH_ALEN); #if defined(CONFIG_POWER_SAVING) RTW_INFO("%s() enable ips & lps\n", __func__); rtw_pm_set_lps(padapter_for_genl, PS_MODE_MAX); rtw_pm_set_ips(padapter_for_genl, IPS_NORMAL); #endif } return ret; } } else { RTW_ERR("%s(): genlmsg_new fail\n", __func__); return -1; } rtw_genl_send_retry_cnt = 0; return 0; } #endif /* CONFIG_ALIBABA_ZEROCONFIG */