1530 lines
44 KiB
C
1530 lines
44 KiB
C
#include <linux/module.h>
|
|
#include <linux/kobject.h>
|
|
#include <linux/kthread.h>
|
|
#include <linux/dcache.h>
|
|
#include <linux/netdevice.h>
|
|
#include <linux/rtnetlink.h>
|
|
#include <net/net_namespace.h>
|
|
#include "apollo.h"
|
|
#include "bh.h"
|
|
#include "hwio.h"
|
|
#include "wsm.h"
|
|
#include "sbus.h"
|
|
#include "iface.h"
|
|
#include "module_fs.h"
|
|
#include "svn_version.h"
|
|
#define PARAMAS_SET BIT(0)
|
|
#define PARAMAS_ON BIT(1)
|
|
static bool enable_echo = true;
|
|
static int num_echo = -1;
|
|
|
|
#define ATBM_SHOW_MSG_MAX_SIZE PAGE_SIZE
|
|
|
|
|
|
#define ATBM_CODE__EXAMPLE_CODE 0
|
|
#define ATBM_CODE__MAX 1
|
|
|
|
extern struct atbm_common *g_hw_priv;
|
|
|
|
#define atbm_show_init(show,_buff) rcu_assign_pointer((show)->show_buff,_buff); \
|
|
(show)->show_count = 0; \
|
|
(show)->show_size = ATBM_SHOW_MSG_MAX_SIZE; \
|
|
(show)->overflow = 0
|
|
#define atbm_show_deinit(show) rcu_assign_pointer((show)->show_buff,NULL); \
|
|
(show)->show_count = 0; \
|
|
(show)->show_size=0; \
|
|
(show)->overflow = 0
|
|
#define atbm_module_show_put(_show,...) \
|
|
do{ \
|
|
int ret = 0; \
|
|
char *_show_buff; \
|
|
rcu_read_lock(); \
|
|
_show_buff = rcu_dereference((_show)->show_buff); \
|
|
if((_show_buff == NULL)||((_show)->overflow == 1) || ((_show)->show_size<=(_show)->show_count)){\
|
|
if(_show_buff) atbm_printk_debug("overflow(%d),show_size(%d),show_count(%d)\n",(_show)->overflow,(_show)->show_size,(_show)->show_count); \
|
|
rcu_read_unlock(); \
|
|
break; \
|
|
} \
|
|
ret = snprintf(_show_buff+(_show)->show_count,(_show)->show_size-(_show)->show_count,__VA_ARGS__); \
|
|
if(ret>=0){ \
|
|
(_show)->show_count+=ret; \
|
|
if((_show)->show_count >= (_show)->show_size){ \
|
|
(_show)->show_count = (_show)->show_size; \
|
|
(_show)->overflow = 1; \
|
|
} \
|
|
} \
|
|
else{ \
|
|
(_show)->overflow = 1; \
|
|
atbm_printk_always("buff overflow(%d)(%d)\n",(_show)->show_size,(_show)->show_count); \
|
|
} \
|
|
rcu_read_unlock(); \
|
|
}while(0)
|
|
|
|
#define atbm_module_put(_show,_src,_len) \
|
|
do{ \
|
|
char *_show_buff; \
|
|
if((_show)->show_count+_len>(_show)->show_size) \
|
|
(_show)->overflow = 1; \
|
|
if((_show)->overflow) break; \
|
|
rcu_read_lock(); \
|
|
_show_buff = rcu_dereference((_show)->show_buff); \
|
|
if(_show_buff == NULL){ \
|
|
rcu_read_unlock(); \
|
|
break; \
|
|
} \
|
|
memcpy(_show_buff+(_show)->show_count,_src,_len); \
|
|
(_show)->show_count += _len; \
|
|
rcu_read_unlock(); \
|
|
}while(0)
|
|
|
|
struct mutex atbm_module_fs_lock;
|
|
#define atbm_modulefs_lock_int() mutex_init(&atbm_module_fs_lock)
|
|
#define atbm_modulefs_lock() mutex_lock(&atbm_module_fs_lock)
|
|
#define atbm_modulefs_unlock() mutex_unlock(&atbm_module_fs_lock)
|
|
#define atbm_modulefs_trylock() mutex_trylock(&atbm_module_fs_lock)
|
|
#define atbm_modulefs_lock_release() mutex_destroy(&atbm_module_fs_lock)
|
|
#define atbm_modulefs_lock_check() lockdep_assert_held(&atbm_module_fs_lock)
|
|
|
|
struct atbm_module_show
|
|
{
|
|
char __rcu *show_buff;
|
|
int show_count;
|
|
int show_size;
|
|
int overflow;
|
|
};
|
|
|
|
struct atbm_sting_s{
|
|
const char *string;
|
|
const char *string_pos;
|
|
struct hlist_node hnode;
|
|
bool found;
|
|
unsigned int len;
|
|
unsigned int params;
|
|
bool (*string_func)(const char *pos_l,const char *pos_r,void *priv);
|
|
void *priv;
|
|
};
|
|
#define ATBM_STRING_MAX_LEN 32
|
|
#define ATBM_STRING_HASHBITS 4
|
|
#define ATBM_STRING_HASHENTRIES (1 << ATBM_STRING_HASHBITS)
|
|
|
|
#define ATBM_STRING_TABLE_INIT(_string,_string_func,_priv) \
|
|
{ \
|
|
.string = _string, \
|
|
.string_pos = NULL, \
|
|
.found = 0, \
|
|
.len = 0, \
|
|
.params = 0, \
|
|
.string_func = _string_func, \
|
|
.priv = _priv, \
|
|
}
|
|
|
|
struct atbm_printk_mask_table_s {
|
|
const char *mask_string;
|
|
const char *mask_info;
|
|
u32 mask_val;
|
|
struct hlist_node string_hnode;
|
|
};
|
|
#define ATBM_PRINTK_MAX_STRING_LEN 32
|
|
#define ATBM_PRINTK_HASHBITS 4
|
|
#define ATBM_PRINTK_HASHENTRIES (1 << ATBM_PRINTK_HASHBITS)
|
|
#define LOG_ON "ON"
|
|
#define LOG_OFF "OFF"
|
|
#define LOG_ALL "OPEN_ALL"
|
|
#define LOG_DEFAULT "DEFAULT"
|
|
#define LOG_CLEAR "CLEAR"
|
|
#define ATBM_BRA_L '['
|
|
#define ATBM_BRA_R ']'
|
|
#define ATBM_ANG_L '<'
|
|
#define ATBM_ANG_R '>'
|
|
|
|
#define ATBM_PARAML ATBM_BRA_L
|
|
#define ATBM_PARAMR ATBM_BRA_R
|
|
#define ATBM_PARAML_S ATBM_ANG_L
|
|
#define ATBM_PARAMR_S ATBM_ANG_R
|
|
|
|
#define atbm_string_invalid(_header) (((_header) != ATBM_SPACE)&&((_header) != ATBM_LINEF)&&((_header) != ATBM_ENTER)&&((_header) != ATBM_TAIL))
|
|
#define OPTION_TABLE_INIT(string,val) \
|
|
{ \
|
|
.opton_string = string, \
|
|
.option_val = val, \
|
|
}
|
|
#define LOG_TABLE_INIT(string,info,val) \
|
|
{ \
|
|
.mask_string = string, \
|
|
.mask_info = info, \
|
|
.mask_val = val, \
|
|
}
|
|
struct atbm_option_table_s {
|
|
const char *opton_string;
|
|
u32 option_val;
|
|
};
|
|
|
|
static const struct atbm_option_table_s option_table[]={
|
|
OPTION_TABLE_INIT(LOG_ON,1),
|
|
OPTION_TABLE_INIT(LOG_OFF,0),
|
|
};
|
|
/*
|
|
*
|
|
*atbm cmd fs control
|
|
*
|
|
*/
|
|
struct atbm_store_cmd_code {
|
|
const char *label;
|
|
const char *cmd_info;
|
|
void __rcu *cmd_private;
|
|
bool (*code_cmd)(struct atbm_store_cmd_code *cmd_store,const char *buf,int len);
|
|
ssize_t (*show_cmd)(struct atbm_store_cmd_code *cmd_store,char *buf,bool show);
|
|
bool echo_enable;
|
|
bool echo_ready;
|
|
struct atbm_module_show echo;
|
|
struct hlist_node hnode;
|
|
struct list_head lhead;
|
|
};
|
|
#define ATBM_SCAN_HASHBITS ATBM_COMMON_HASHBITS
|
|
#define ATBM_SCAN_HASHENTRIES (1 << ATBM_SCAN_HASHBITS)
|
|
struct atbm_conf_ascii{
|
|
u8 *asciis;
|
|
int len;
|
|
};
|
|
struct atbm_conf_ifname{
|
|
u8 if_name[IFNAMSIZ];
|
|
u8 size;
|
|
};
|
|
|
|
struct atbm_conf_channels{
|
|
u8 *channels;
|
|
u8 n_channels;
|
|
};
|
|
|
|
struct atbm_conf_ssids{
|
|
struct cfg80211_ssid *ssids;
|
|
u8 n_ssids;
|
|
};
|
|
|
|
struct atbm_conf_macs{
|
|
struct ieee80211_internal_mac *mac;
|
|
u8 n_macs;
|
|
};
|
|
|
|
struct atbm_conf_ies{
|
|
u8 *ies;
|
|
u8 ie_len;
|
|
u8 atbm_ie;
|
|
};
|
|
struct atbm_conf_integer{
|
|
int *integers;
|
|
u8 n_integers;
|
|
};
|
|
struct atbm_conf_string
|
|
{
|
|
char *strings;
|
|
struct hlist_node hnode;
|
|
bool set;
|
|
};
|
|
struct atbm_config_string_hash
|
|
{
|
|
struct hlist_head hlist_head[ATBM_COMMON_HASHENTRIES];
|
|
bool empty;
|
|
};
|
|
struct atbm_module_ap_conf{
|
|
struct atbm_conf_ifname ifname;
|
|
struct atbm_conf_channels channel;
|
|
struct atbm_conf_ssids ssid;
|
|
struct atbm_conf_macs bssid;
|
|
struct atbm_conf_ascii psk;
|
|
};
|
|
struct atbm_module_halt_conf{
|
|
struct atbm_conf_ifname ifname;
|
|
};
|
|
struct atbm_echo_params{
|
|
int num;
|
|
};
|
|
#define ATBM_CMD_MAX_STRING_LEN 32
|
|
#define ATBM_CMD_HASHBITS 4
|
|
#define ATBM_CMD_HASHENTRIES (1 << ATBM_CMD_HASHBITS)
|
|
|
|
#define ATBM_CODE_STR__ATTR_EXAMPLE_INFO "show example"
|
|
#define ATBM_CODE_STR__ATTR_HELP_INFO "show all cmd help info"
|
|
#define ATBM_CODE_STR__ATTR_ENABLE_ECHO_INFO "enable echo parmas:enable_echo num_echo=[1]"
|
|
#define ATBM_CODE_STR__ATTR_DISABLE_ECHO_INFO "disable echo:disable_echo"
|
|
#define ATBM_CODE_STR__ATTR_AP_CONF_INFO "set ap configs:ap_config ifname=[xxx] channel=[x] ssid=[ap] bssid=[xx:xx:xx:xx:xx:xx] psk=[password]"
|
|
|
|
|
|
#define ATBM_CODE_STR__ATTR_EXAMPLE "example"
|
|
#define ATBM_CODE_STR__ATTR_HELP "help"
|
|
#define ATBM_CODE_STR__ATTR_ENABLE_ECHO "enable_echo"
|
|
#define ATBM_CODE_STR__ATTR_DISABLE_ECHO "disable_echo"
|
|
#define ATBM_CODE_STR__ATTR_CLEAR_FREQ "clear_freq"
|
|
#define ATBM_CODE_STR__ATTR_AP_CONF "ap_config"
|
|
|
|
|
|
|
|
struct hlist_head atbm_cmd_hash_head[ATBM_CMD_HASHENTRIES];
|
|
struct list_head atbm_cmd_echo_ready_list;
|
|
static char *backup_show = NULL;
|
|
static int backup_show_size = 0;
|
|
static int ready_list_num = 0;
|
|
|
|
#define ATBM_CMD_INIT(cmd_code,info,_store_cmd,_show_cmd)\
|
|
{ \
|
|
.label = cmd_code, \
|
|
.cmd_info = info, \
|
|
.code_cmd = _store_cmd, \
|
|
.show_cmd = _show_cmd, \
|
|
.cmd_private = NULL, \
|
|
}
|
|
static bool atbm_module_attr_echo_enable(struct atbm_store_cmd_code *cmd_store,const char *buf,int len);
|
|
static bool atbm_module_attr_echo_disable(struct atbm_store_cmd_code *cmd_store,const char *buf,int len);
|
|
static bool atbm_module_attr_example(struct atbm_store_cmd_code *cmd_store,const char *buf,int len);
|
|
static bool atbm_module_attr_help(struct atbm_store_cmd_code *cmd_store,const char *buf,int len);
|
|
static ssize_t atbm_module_attr_default_show(struct atbm_store_cmd_code *cmd_code,char *buf,bool show);
|
|
#ifndef CONFIG_ATBM_SDIO_ATCMD
|
|
static bool atbm_module_attr_set_ap_config(struct atbm_store_cmd_code *cmd_store,const char *buf,int len);
|
|
#endif
|
|
struct atbm_store_cmd_code cmd_code_buff[]={
|
|
ATBM_CMD_INIT(ATBM_CODE_STR__ATTR_HELP,ATBM_CODE_STR__ATTR_HELP_INFO,atbm_module_attr_help,atbm_module_attr_default_show),
|
|
ATBM_CMD_INIT(ATBM_CODE_STR__ATTR_EXAMPLE,ATBM_CODE_STR__ATTR_EXAMPLE_INFO,atbm_module_attr_example,atbm_module_attr_default_show),
|
|
ATBM_CMD_INIT(ATBM_CODE_STR__ATTR_DISABLE_ECHO,ATBM_CODE_STR__ATTR_DISABLE_ECHO_INFO,atbm_module_attr_echo_disable,atbm_module_attr_default_show),
|
|
ATBM_CMD_INIT(ATBM_CODE_STR__ATTR_ENABLE_ECHO,ATBM_CODE_STR__ATTR_ENABLE_ECHO_INFO,atbm_module_attr_echo_enable,atbm_module_attr_default_show),
|
|
#ifndef CONFIG_ATBM_SDIO_ATCMD
|
|
ATBM_CMD_INIT(ATBM_CODE_STR__ATTR_AP_CONF,ATBM_CODE_STR__ATTR_AP_CONF_INFO,atbm_module_attr_set_ap_config,atbm_module_attr_default_show),
|
|
#endif
|
|
};
|
|
|
|
static unsigned int atbm_hash_string_len(const char *pos,unsigned int pos_len)
|
|
{
|
|
unsigned int i;
|
|
unsigned int j;
|
|
|
|
if(pos == NULL){
|
|
return 0;
|
|
}
|
|
for(i = 0;i<pos_len;i++){
|
|
if(pos[i] != ATBM_SPACE)
|
|
continue;
|
|
for(j = i;j<pos_len;j++){
|
|
if(pos[j] != ATBM_SPACE)
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
static int atbm_cmd_string_split(const char *pos,int len,const char **pos_l,const char **pos_r)
|
|
{
|
|
int i = 0;
|
|
int j = 0;
|
|
const char *l = NULL;
|
|
const char *r = NULL;
|
|
char next_pos;
|
|
|
|
if(len == 0){
|
|
return -1;
|
|
}
|
|
atbm_printk_debug("%s:%d %s\n",__func__,len,pos);
|
|
for(i = 0;i<len;i++){
|
|
|
|
if((pos[i] == ATBM_PARAMR)||(pos[i] == ATBM_PARAMR_S)){
|
|
atbm_printk_debug("%s:left pos err\n",__func__);
|
|
return -1;
|
|
}
|
|
|
|
if((pos[i] != ATBM_PARAML)&&(pos[i] != ATBM_PARAML_S)){
|
|
continue;
|
|
}
|
|
l = &pos[i];
|
|
next_pos = pos[i] == ATBM_PARAML ? ATBM_PARAMR:ATBM_PARAMR_S;
|
|
for(j = i+1;j<len;j++){
|
|
|
|
if((pos[j] == ATBM_PARAML)||(pos[j] == ATBM_PARAML_S)){
|
|
atbm_printk_debug("%s:right pos err\n",__func__);
|
|
return -1;
|
|
}
|
|
|
|
if(pos[j] != next_pos){
|
|
continue;
|
|
}
|
|
r = &pos[j];
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if((l == NULL) && (r == NULL)){
|
|
return 0;
|
|
}else if((l == NULL) || (r == NULL)){
|
|
return -1;
|
|
}
|
|
|
|
*pos_l = l;
|
|
*pos_r = r;
|
|
|
|
return *l == ATBM_PARAML ? 1: 2;
|
|
}
|
|
static bool atbm_string_parase_echo(const char *pos_l,const char *pos_r,void *priv)
|
|
{
|
|
#define ECHO_ENABLE "enable"
|
|
#define ECHO_DISABLE "disable"
|
|
struct atbm_store_cmd_code *cmd_store = (struct atbm_store_cmd_code *)priv;
|
|
|
|
if(pos_r <= pos_l){
|
|
atbm_printk_debug("%s:len err\n",__func__);
|
|
return false;
|
|
}
|
|
|
|
if((strlen(ECHO_ENABLE) == pos_r-pos_l)&&(!memcmp(ECHO_ENABLE,pos_l, pos_r-pos_l))){
|
|
atbm_printk_debug("%s:echo enanle\n",__func__);
|
|
cmd_store->echo_enable = true;
|
|
}else if((strlen(ECHO_DISABLE) == pos_r-pos_l)&&(!memcmp(ECHO_DISABLE,pos_l, pos_r-pos_l))){
|
|
atbm_printk_debug("%s:echo disable\n",__func__);
|
|
cmd_store->echo_enable = false;
|
|
}else {
|
|
atbm_printk_debug("%s:unkown echo %s\n",__func__,pos_l);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
static bool atbm_string_parase(struct atbm_store_cmd_code *cmd_store,struct atbm_sting_s *string_table,unsigned int table_size,const char *string,unsigned int string_len)
|
|
{
|
|
#define CMD_ECHO_STR "echo="
|
|
unsigned int index = 0;
|
|
const char *pos = string;
|
|
const char *pos_end = string+string_len;
|
|
const char *nospace_pos;
|
|
const char *target_pos;
|
|
struct hlist_head *hhead;
|
|
struct hlist_node *node;
|
|
struct hlist_head atbm_string_hash_head[ATBM_STRING_HASHENTRIES];
|
|
struct atbm_sting_s *string_node;
|
|
struct atbm_sting_s echo_str;
|
|
unsigned int hash_index = 0;
|
|
|
|
if(table_size < 0){
|
|
return false;
|
|
}
|
|
|
|
memset(&echo_str,0,sizeof(struct atbm_sting_s));
|
|
|
|
echo_str.string = CMD_ECHO_STR;
|
|
echo_str.priv = cmd_store;
|
|
echo_str.string_func = atbm_string_parase_echo;
|
|
atbm_common_hash_list_init(atbm_string_hash_head,ATBM_STRING_HASHENTRIES);
|
|
/*
|
|
*first add echo string
|
|
*/
|
|
hash_index = atbm_hash_index(echo_str.string,strlen(echo_str.string),ATBM_STRING_HASHBITS);
|
|
hlist_add_head(&echo_str.hnode,&atbm_string_hash_head[hash_index]);
|
|
|
|
/*
|
|
*second add requset string
|
|
*/
|
|
for(index = 0;index<table_size;index++){
|
|
unsigned int hash_index = atbm_hash_index(string_table[index].string,
|
|
strlen(string_table[index].string),ATBM_STRING_HASHBITS);
|
|
BUG_ON(strlen(string_table[index].string) > ATBM_STRING_MAX_LEN);
|
|
|
|
hhead = &atbm_string_hash_head[hash_index];
|
|
|
|
hlist_for_each(node,hhead){
|
|
string_node = hlist_entry(node,struct atbm_sting_s,hnode);
|
|
if ((!strncmp(string_node->string, string_table[index].string, strlen(string_table[index].string)))&&
|
|
(strlen(string_table[index].string) == strlen(string_node->string))){
|
|
atbm_printk_debug("%s:string_node(%s) already in list\n",__func__,string_node->string);
|
|
return false;
|
|
}
|
|
}
|
|
hlist_add_head(&string_table[index].hnode,&atbm_string_hash_head[hash_index]);
|
|
atbm_printk_debug("%s:[%s]->[%d]\n",__func__,string_table[index].string,hash_index);
|
|
}
|
|
|
|
atbm_printk_debug("%s:len:%d tring:%s\n",__func__,string_len,pos);
|
|
while(pos<pos_end){
|
|
next_str:
|
|
/*
|
|
*pos <= pos_end will return null,and break the loop
|
|
*/
|
|
nospace_pos = atbm_skip_space(pos,pos_end-pos);
|
|
|
|
if(nospace_pos == NULL){
|
|
atbm_printk_debug("%s nospace_pos == NULL\n",__func__);
|
|
return pos == string ? false: true;
|
|
}
|
|
|
|
pos = nospace_pos;
|
|
atbm_printk_debug("%s:len:%zu nospace_pos:%s\n",__func__,pos_end-pos,nospace_pos);
|
|
if(pos[0] == ATBM_TAIL)
|
|
return pos == string?false: true;
|
|
else if((pos[0] == ATBM_LINEF)||(pos[0] == ATBM_ENTER))
|
|
return pos == string?false: true;
|
|
/*
|
|
*find the postion of cmd end =
|
|
*/
|
|
target_pos = memchr(pos, ATBM_EQUAL, pos_end-pos);
|
|
if(target_pos == NULL){
|
|
atbm_printk_always("%s:can not cmd =\n",__func__);
|
|
return false;
|
|
}
|
|
atbm_printk_debug("%s:len:%zu,str %s\n",__func__,target_pos-pos+1,pos);
|
|
hhead = atbm_hash_list(pos,target_pos-pos+1,atbm_string_hash_head,ATBM_STRING_HASHBITS);
|
|
|
|
if(hhead == NULL){
|
|
atbm_printk_always("%s:hhead = NULL\n",__func__);
|
|
return false;
|
|
}
|
|
hlist_for_each(node,hhead){
|
|
|
|
string_node = hlist_entry(node,struct atbm_sting_s,hnode);
|
|
atbm_printk_debug("%s:string_node(%s)(%zu),target:%zu:%s\n",__func__,
|
|
string_node->string,strlen(string_node->string),target_pos-pos+1,pos);
|
|
if ((!strncmp(pos, string_node->string,target_pos-pos+1))&&
|
|
(strlen(string_node->string) == target_pos-pos+1)){
|
|
|
|
const char *tmp_pos = NULL;
|
|
if(string_node->found == true){
|
|
atbm_printk_debug("%s:fund same string(%s)\n",__func__,string_node->string);
|
|
return false;
|
|
}
|
|
tmp_pos = atbm_skip_space(target_pos+1,string_len - (target_pos+1-string));
|
|
|
|
if(tmp_pos == NULL){
|
|
atbm_printk_always("%s:tmp_pos == NULL\n",__func__);
|
|
return false;
|
|
}
|
|
string_node->found = true;
|
|
string_node->string_pos = tmp_pos;
|
|
string_node->len = pos_end-tmp_pos;
|
|
|
|
if((tmp_pos[0] != ATBM_PARAML)&&(tmp_pos[0] != ATBM_PARAML_S)){
|
|
/*
|
|
*find the postion of cmd end,use space between tow string
|
|
*some cmd not need space ,so find enter or end of line
|
|
*/
|
|
pos = memchr(tmp_pos, ATBM_SPACE, pos_end-tmp_pos);
|
|
if(pos == NULL){
|
|
pos = memchr(tmp_pos, ATBM_ENTER, pos_end-tmp_pos);
|
|
if(pos == NULL)
|
|
pos = memchr(tmp_pos, ATBM_LINEF, pos_end-tmp_pos);
|
|
}
|
|
if(string_node->string_func){
|
|
if(pos == NULL) pos=pos_end;
|
|
if(string_node->string_func(tmp_pos,pos,string_node->priv) == false){
|
|
atbm_printk_err("%s:[%s] err tmp_pos (%p) pos (%p) %s\n",__func__,string_node->string,tmp_pos,pos,pos);
|
|
return false;
|
|
}
|
|
}
|
|
string_node->params = 1;
|
|
}else {
|
|
const char *pos_l;
|
|
const char *pos_r;
|
|
int res = 0;
|
|
|
|
pos_r = tmp_pos;
|
|
pos_l = tmp_pos;
|
|
while(pos_r<pos_end){
|
|
|
|
res = atbm_cmd_string_split(pos_l,pos_end-pos_l,&pos_l,&pos_r);
|
|
|
|
if(res<=0){
|
|
atbm_printk_err("%s not find l and r %s\n",__func__,pos);
|
|
return false;
|
|
}
|
|
if((pos_r-pos_l) == 1){
|
|
atbm_printk_err("%s param is null %s\n",__func__,pos);
|
|
return false;
|
|
}
|
|
string_node->params++;
|
|
if(string_node->string_func){
|
|
if(string_node->string_func(pos_l+1,pos_r,string_node->priv) == false){
|
|
atbm_printk_err("%s:[%s] err pos_l (%p) pos_r (%p) %s\n",__func__,string_node->string,pos_l+1,pos_r,pos_l+1);
|
|
return false;
|
|
}
|
|
}
|
|
pos_r++;
|
|
pos_l = pos_r;
|
|
|
|
if((pos_l[0]!=ATBM_PARAML)&&(pos_l[0]!=ATBM_PARAML_S)){
|
|
if(atbm_string_invalid(pos_l[0])){
|
|
atbm_printk_err("%s param format err %s\n",__func__,pos);
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
pos = pos_r;
|
|
}
|
|
|
|
|
|
if(pos == NULL)
|
|
pos = pos_end;
|
|
else
|
|
string_node->len = pos-tmp_pos;
|
|
atbm_printk_debug("[%s]:len %d,pos %s\n",string_node->string,string_node->len,string_node->string_pos);
|
|
goto next_str;
|
|
}
|
|
}
|
|
|
|
atbm_printk_always("%s:string is err %s\n",__func__,pos);
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
static void *atbm_store_cmd_init_cmd_private(struct atbm_store_cmd_code *cmd_store,int len,gfp_t gfp)
|
|
{
|
|
void *cmd_private;
|
|
|
|
cmd_private = rcu_dereference(cmd_store->cmd_private);
|
|
if(cmd_private){
|
|
if(cmd_store->show_cmd)
|
|
cmd_store->show_cmd(cmd_store,NULL,false);
|
|
rcu_assign_pointer(cmd_store->cmd_private,NULL);
|
|
synchronize_rcu();
|
|
|
|
atbm_kfree(cmd_private);
|
|
}
|
|
|
|
cmd_private = atbm_kzalloc(len,gfp);
|
|
|
|
return cmd_private;
|
|
}
|
|
static struct hlist_head *atbm_cmd_hash_list(const char *string,unsigned int len)
|
|
{
|
|
return atbm_hash_list(string,len,atbm_cmd_hash_head,ATBM_CMD_HASHBITS);
|
|
}
|
|
|
|
|
|
static struct atbm_store_cmd_code *atbm_store_cmd_find_cmd(const char *pos,unsigned int pos_len)
|
|
{
|
|
unsigned char string_len = 0;
|
|
struct hlist_head *hlist = NULL;
|
|
struct atbm_store_cmd_code *cmd_code;
|
|
struct hlist_node *node;
|
|
|
|
if(ATBM_CMD_MAX_STRING_LEN<pos_len){
|
|
atbm_printk_always("%s:[%s] pos_len is too long\n",__func__,pos);
|
|
return NULL;
|
|
}
|
|
|
|
string_len = atbm_hash_string_len(pos,pos_len);
|
|
|
|
if(string_len == 0){
|
|
atbm_printk_always("%s:[%s] cmd len err\n",__func__,pos);
|
|
return NULL;
|
|
}
|
|
|
|
hlist = atbm_cmd_hash_list(pos,string_len);
|
|
|
|
hlist_for_each(node,hlist){
|
|
cmd_code = hlist_entry(node,struct atbm_store_cmd_code,hnode);
|
|
if ((!strncmp(pos, cmd_code->label, string_len))&&
|
|
(string_len == strlen(cmd_code->label))){
|
|
return cmd_code;
|
|
}
|
|
}
|
|
atbm_printk_always("%s:[%s] can not fund\n",__func__,pos);
|
|
return NULL;
|
|
}
|
|
static bool atbm_store_cmd_init_show(struct atbm_module_show *show)
|
|
{
|
|
char *show_buff;
|
|
|
|
if((show_buff = rcu_dereference(show->show_buff)) == NULL){
|
|
show_buff = atbm_kzalloc(ATBM_SHOW_MSG_MAX_SIZE,GFP_KERNEL);
|
|
}
|
|
|
|
if(show_buff == NULL){
|
|
return false;
|
|
}
|
|
atbm_show_deinit(show);
|
|
atbm_show_init(show,show_buff);
|
|
|
|
return true;
|
|
}
|
|
|
|
static void atbm_store_cmd_deinit_show(struct atbm_module_show *show)
|
|
{
|
|
char *show_buff = rcu_dereference(show->show_buff);
|
|
|
|
atbm_show_deinit(show);
|
|
if(show_buff){
|
|
synchronize_rcu();
|
|
atbm_kfree(show_buff);
|
|
atbm_printk_debug("%s:free(%p)\n",__func__,show_buff);
|
|
}
|
|
}
|
|
static ssize_t atbm_module_attr_default_show(struct atbm_store_cmd_code *cmd_code,char *buf,bool show)
|
|
{
|
|
struct atbm_module_show echo_show;
|
|
atbm_show_init(&echo_show,buf);
|
|
if(show == true)
|
|
atbm_module_show_put(&echo_show,cmd_code->echo.show_buff);
|
|
return echo_show.show_count;
|
|
}
|
|
static bool atbm_module_attr_example(struct atbm_store_cmd_code *cmd_store,const char *buf,int len)
|
|
{
|
|
atbm_module_show_put(&cmd_store->echo,"atbm module cmd example\n");
|
|
atbm_module_show_put(&cmd_store->echo,"\n");
|
|
atbm_printk_always( "%s\n",__func__);
|
|
return true;
|
|
}
|
|
static bool atbm_module_attr_help(struct atbm_store_cmd_code *cmd_store,const char *buf,int len)
|
|
{
|
|
unsigned int index = 0;
|
|
struct atbm_module_show *show = &cmd_store->echo;
|
|
|
|
atbm_module_show_put(show,LIGHT"Atbm Cmd Help-->:"NORMAL ENTER);
|
|
for(index = 0;index<ARRAY_SIZE(cmd_code_buff);index++){
|
|
atbm_module_show_put(show,LIGHT"[%s]"NORMAL":%s\n",cmd_code_buff[index].label,cmd_code_buff[index].cmd_info);
|
|
}
|
|
atbm_printk_always( "%s\n",__func__);
|
|
return true;
|
|
}
|
|
|
|
#ifndef CONFIG_ATBM_SDIO_ATCMD
|
|
static struct atbm_vif * atbm_module_get_sdata_by_name(const char *name)
|
|
{
|
|
struct net_device *net_dev = NULL;
|
|
struct atbm_vif *vif;
|
|
|
|
ASSERT_RTNL();
|
|
net_dev = __dev_get_by_name(&init_net,name);
|
|
|
|
if(net_dev == NULL){
|
|
return NULL;
|
|
}
|
|
|
|
vif = atbm_dev_to_vif(net_dev);
|
|
|
|
if (vif->ndev == net_dev)
|
|
return vif;
|
|
|
|
atbm_printk_err("%s: can not get(%s) dev\n",__func__,name);
|
|
return NULL;
|
|
}
|
|
static bool atbm_module_config_ascii(const char *posl,const char *posr,void *priv)
|
|
{
|
|
struct atbm_conf_ascii *asciis = (struct atbm_conf_ascii *)priv;
|
|
u8 len = posr - posl;
|
|
|
|
atbm_printk_debug("%s:posl(%p),posr(%p) %s\n",__func__,posl,posr,posl);
|
|
|
|
if(asciis == NULL){
|
|
atbm_printk_err("%s:priv NULL(%p),\n",__func__,priv);
|
|
return false;
|
|
}
|
|
|
|
if(asciis->len != 0){
|
|
atbm_printk_err("%s:asciis has been set\n",__func__);
|
|
return false;
|
|
}
|
|
|
|
asciis->asciis = atbm_kzalloc(len, GFP_KERNEL);
|
|
|
|
if(asciis->asciis == NULL){
|
|
return false;
|
|
}
|
|
|
|
memcpy(asciis->asciis,posl,len);
|
|
asciis->len = len;
|
|
|
|
return true;
|
|
}
|
|
static bool atbm_module_config_ifname(const char *posl,const char *posr,void *priv)
|
|
{
|
|
struct atbm_conf_ifname *conf_ifname = (struct atbm_conf_ifname *)priv;
|
|
u8 len = posr - posl;
|
|
|
|
atbm_printk_debug("%s:posl(%p),posr(%p) %s\n",__func__,posl,posr,posl);
|
|
|
|
if(conf_ifname == NULL){
|
|
atbm_printk_err("%s:priv NULL(%p),\n",__func__,priv);
|
|
return false;
|
|
}
|
|
|
|
if(conf_ifname->size != 0){
|
|
atbm_printk_err("%s:if name has been set\n",__func__);
|
|
return false;
|
|
}
|
|
|
|
if(len > IFNAMSIZ){
|
|
atbm_printk_err("%s:if name size too long\n",__func__);
|
|
return false;
|
|
}
|
|
|
|
memcpy(conf_ifname->if_name,posl,len);
|
|
conf_ifname->size = len;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool atbm_module_config_channels(const char *posl,const char *posr,void *priv)
|
|
{
|
|
struct atbm_conf_channels *channels = (struct atbm_conf_channels *)priv;
|
|
|
|
u8 *new_channels = channels->channels;
|
|
u8 *pos_channel;
|
|
int channel_index = 0;
|
|
|
|
atbm_printk_debug("%s:posl(%p),posr(%p) %s\n",__func__,posl,posr,posl);
|
|
if(priv == NULL){
|
|
atbm_printk_err("%s:priv NULL(%p),\n",__func__,priv);
|
|
return false;
|
|
}
|
|
if(channels->n_channels>=ATBM_MAX_SCAN_CHANNEL){
|
|
atbm_printk_err("%s:channles too mach(%d)\n",__func__,channels->n_channels);
|
|
return false;
|
|
}
|
|
|
|
if((posr - posl <= 0) || (posr-posl>2)){
|
|
atbm_printk_err("%s:channles len err\n",__func__);
|
|
return false;
|
|
}
|
|
|
|
if(new_channels && channels->n_channels){
|
|
|
|
new_channels = atbm_krealloc(channels->channels,channels->n_channels+1,GFP_KERNEL);
|
|
if(new_channels == NULL){
|
|
atbm_printk_err("%s:channles alloc err\n",__func__);
|
|
return false;
|
|
}
|
|
|
|
}else {
|
|
new_channels = atbm_kzalloc(1,GFP_KERNEL);
|
|
|
|
if(new_channels == NULL){
|
|
atbm_printk_err("%s:channles kzalloc err\n",__func__);
|
|
return false;
|
|
}
|
|
}
|
|
channels->channels = new_channels;
|
|
pos_channel = new_channels+channels->n_channels;
|
|
|
|
if(atbm_accsii_to_int(posl,posr-posl,&channel_index) == false){
|
|
atbm_printk_err("%s:channel_index (%d) err\n",__func__,channel_index);
|
|
return false;
|
|
}
|
|
|
|
if(channel_index>50){
|
|
atbm_printk_err("%s:channel_index (%d) err\n",__func__,channel_index);
|
|
return false;
|
|
}
|
|
|
|
channels->n_channels++;
|
|
*pos_channel = (u8)channel_index;
|
|
return true;
|
|
}
|
|
static bool atbm_module_config_ssids(const char *posl,const char *posr,void *priv)
|
|
{
|
|
struct atbm_conf_ssids *ssids = (struct atbm_conf_ssids *)priv;
|
|
struct cfg80211_ssid *new_ssid = ssids->ssids;
|
|
struct cfg80211_ssid *pos_ssid = NULL;
|
|
|
|
atbm_printk_debug("%s:posl(%p),posr(%p) %s\n",__func__,posl,posr,posl);
|
|
if(priv == NULL){
|
|
atbm_printk_err("%s:priv NULL(%p),\n",__func__,priv);
|
|
return false;
|
|
}
|
|
if(ssids->n_ssids>=ATBM_MAX_SCAN_SSID){
|
|
atbm_printk_err("%s:ssid to mach(%d)\n",__func__,ssids->n_ssids);
|
|
return false;
|
|
}
|
|
if((posr - posl <= 0) || (posr-posl>IEEE80211_MAX_SSID_LEN)){
|
|
atbm_printk_err("%s:channles len err\n",__func__);
|
|
return false;
|
|
}
|
|
|
|
if(new_ssid&&ssids->n_ssids){
|
|
new_ssid = atbm_krealloc(ssids->ssids,sizeof(struct cfg80211_ssid)*(ssids->n_ssids+1),GFP_KERNEL);
|
|
if(new_ssid == NULL){
|
|
atbm_printk_err("%s:channles realloc err\n",__func__);
|
|
return false;
|
|
}
|
|
}else {
|
|
new_ssid = atbm_kzalloc(sizeof(struct cfg80211_ssid),GFP_KERNEL);
|
|
|
|
if(new_ssid == NULL){
|
|
atbm_printk_err("%s:channles kzalloc err\n",__func__);
|
|
return false;
|
|
}
|
|
}
|
|
ssids->ssids = new_ssid;
|
|
pos_ssid = new_ssid + ssids->n_ssids;
|
|
|
|
memcpy(pos_ssid->ssid,posl,posr-posl);
|
|
pos_ssid->ssid_len = posr-posl;
|
|
ssids->n_ssids++;
|
|
|
|
atbm_printk_always("%s: ssid (%s) ssid_len(%d) n_ssids(%d)\n",__func__,pos_ssid->ssid,pos_ssid->ssid_len,ssids->n_ssids);
|
|
return true;
|
|
}
|
|
|
|
static bool atbm_module_config_macs(const char *posl,const char *posr,void *priv)
|
|
{
|
|
struct atbm_conf_macs *macs = (struct atbm_conf_macs *)priv;
|
|
|
|
struct ieee80211_internal_mac *new_mac = macs->mac;
|
|
struct ieee80211_internal_mac *pos_mac = NULL;
|
|
int i;
|
|
u8 hex;
|
|
u8 mac_begin = 0;
|
|
u8 mac_len = 0;
|
|
|
|
atbm_printk_debug("%s:posl(%p),posr(%p) %s\n",__func__,posl,posr,posl);
|
|
if(priv == NULL){
|
|
atbm_printk_err("%s:priv NULL(%p),\n",__func__,priv);
|
|
return false;
|
|
}
|
|
if(posr-posl != 17){
|
|
atbm_printk_err("%s:mac len err(%zu),\n",__func__,posr-posl);
|
|
return false;
|
|
}
|
|
if(macs->n_macs>=ATBM_MAX_SCAN_MAC_FILTER){
|
|
atbm_printk_err("%s:mac to mach(%d),\n",__func__,macs->n_macs);
|
|
return false;
|
|
}
|
|
if(macs->n_macs&&new_mac){
|
|
new_mac = atbm_krealloc(macs->mac,sizeof(struct ieee80211_internal_mac)*(macs->n_macs+1),GFP_KERNEL);
|
|
|
|
if(new_mac == NULL){
|
|
atbm_printk_err("%s:mac realloc err\n",__func__);
|
|
return false;
|
|
}
|
|
}else {
|
|
new_mac = atbm_kzalloc(sizeof(struct ieee80211_internal_mac),GFP_KERNEL);
|
|
|
|
if(new_mac == NULL){
|
|
atbm_printk_err("%s:mac kzalloc err\n",__func__);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
macs->mac = new_mac;
|
|
pos_mac = macs->mac+macs->n_macs;
|
|
|
|
for(i=0;i<posr-posl;i++){
|
|
|
|
if(posl[i] == ':'){
|
|
mac_len++;
|
|
mac_begin = 0;
|
|
continue;
|
|
}
|
|
|
|
if(mac_len>=6){
|
|
atbm_printk_err("%s:mac len,%d\n",__func__,mac_len);
|
|
return false;
|
|
}
|
|
|
|
if(mac_begin>1){
|
|
atbm_printk_err("%s:mac err,mac_begin %d\n",__func__,mac_begin);
|
|
return false;
|
|
}
|
|
if (atbm_accsii_to_hex(posl[i],&hex) == false){
|
|
atbm_printk_err("%s:scan_macs %d\n",__func__,posl[i]);
|
|
return false;
|
|
}
|
|
pos_mac->mac[mac_len] *= 16;
|
|
|
|
pos_mac->mac[mac_len] += hex;
|
|
|
|
mac_begin++;
|
|
}
|
|
|
|
if(mac_len != 5){
|
|
atbm_printk_err("%s:mac len err %d\n",__func__,mac_len);
|
|
return false;
|
|
}
|
|
macs->n_macs++;
|
|
atbm_printk_always("%s:mac[%pM]\n",__func__,pos_mac->mac);
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
static bool atbm_module_echo_enable_num_echo(const char *posl,const char *posr,void *priv)
|
|
{
|
|
struct atbm_echo_params *echo_params = (struct atbm_echo_params *)priv;
|
|
atbm_printk_debug("%s:posl(%p),posr(%p) %s\n",__func__,posl,posr,posl);
|
|
|
|
if(priv == NULL){
|
|
atbm_printk_err("%s:priv NULL(%p),\n",__func__,priv);
|
|
return false;
|
|
}
|
|
|
|
if(echo_params->num != -1){
|
|
atbm_printk_err("%s:echo_params->num err(%d),\n",__func__,echo_params->num);
|
|
return false;
|
|
}
|
|
|
|
if((posr - posl <= 0) || (posr-posl>5)){
|
|
atbm_printk_err("%s: params too long\n",__func__);
|
|
return false;
|
|
}
|
|
|
|
if(atbm_accsii_to_int(posl,posr-posl,&echo_params->num) == false){
|
|
atbm_printk_err("%s:echo_params->num (%d) err\n",__func__,echo_params->num);
|
|
echo_params->num = -1;
|
|
return false;
|
|
}
|
|
|
|
if((echo_params->num<0)&&(echo_params->num != -1)){
|
|
atbm_printk_err("%s:echo_params->num (%d) is negtive\n",__func__,echo_params->num);
|
|
echo_params->num = -1;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
static bool atbm_module_attr_echo_enable(struct atbm_store_cmd_code *cmd_store,const char *buf,int len)
|
|
{
|
|
bool res = true;
|
|
const char* info = buf;
|
|
void *cmd_private = NULL;
|
|
struct atbm_echo_params *echo_params;
|
|
|
|
enable_echo = true;
|
|
cmd_store->echo_enable = true;
|
|
|
|
cmd_private = atbm_store_cmd_init_cmd_private(cmd_store,sizeof(struct atbm_echo_params),GFP_KERNEL);
|
|
|
|
if(cmd_private == NULL){
|
|
res = false;
|
|
goto exit;
|
|
}
|
|
echo_params = (struct atbm_echo_params *)cmd_private;
|
|
echo_params->num = -1;
|
|
rcu_assign_pointer(cmd_store->cmd_private,cmd_private);
|
|
|
|
|
|
info = atbm_skip_space(buf,len);
|
|
|
|
/*
|
|
*parmas start end and channels
|
|
*/
|
|
if(info){
|
|
#define NUM_ECHO "num_echo="
|
|
struct atbm_sting_s req_string[]={
|
|
ATBM_STRING_TABLE_INIT(NUM_ECHO,atbm_module_echo_enable_num_echo,cmd_store->cmd_private),
|
|
};
|
|
if(atbm_string_parase(cmd_store,req_string,ARRAY_SIZE(req_string),info,len-(info-buf))==false){
|
|
atbm_printk_always("%s:channel_select %s err\n",__func__,info);
|
|
res = false;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
num_echo = echo_params->num;
|
|
res = true;
|
|
atbm_printk_err("%s:num_echo(%d)\n",__func__,num_echo);
|
|
exit:
|
|
if(cmd_private){
|
|
atbm_kfree(cmd_private);
|
|
rcu_assign_pointer(cmd_store->cmd_private,NULL);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
static bool atbm_module_attr_echo_disable(struct atbm_store_cmd_code *cmd_store,const char *buf,int len)
|
|
{
|
|
bool res = true;
|
|
|
|
if(buf != NULL || len != 0){
|
|
atbm_printk_err("%s:len(%d)(%p) err\n",__func__,len,buf);
|
|
res = false;
|
|
goto exit;
|
|
}
|
|
|
|
enable_echo = false;
|
|
cmd_store->echo_enable = true;
|
|
exit:
|
|
return res;
|
|
}
|
|
/*
|
|
*set ap configs:ap_config ifname=[xxx] channel=[x] ssid=[ap] bssid=[xx:xx:xx:xx:xx:xx]
|
|
*/
|
|
#ifndef CONFIG_ATBM_SDIO_ATCMD
|
|
static bool atbm_module_attr_set_ap_config(struct atbm_store_cmd_code *cmd_store,const char *buf,int len)
|
|
{
|
|
bool res = true;
|
|
struct atbm_module_ap_conf ap_config;
|
|
const char* select_info = buf;
|
|
struct atbm_vif *vif = NULL;
|
|
struct atbm_ap_config *conf;
|
|
rtnl_lock();
|
|
|
|
select_info = atbm_skip_space(buf,len);
|
|
memset(&ap_config,0,sizeof(struct atbm_module_ap_conf));
|
|
|
|
if(select_info){
|
|
#define CONF_IFNAME "ifname="
|
|
#define CONF_CHANNEL "channel="
|
|
#define CONF_SSID "ssid="
|
|
#define CONF_BSSID "bssid="
|
|
#define CONF_PSK "psk="
|
|
|
|
struct atbm_sting_s req_string[]={
|
|
ATBM_STRING_TABLE_INIT(CONF_IFNAME,atbm_module_config_ifname,&ap_config.ifname),
|
|
ATBM_STRING_TABLE_INIT(CONF_CHANNEL,atbm_module_config_channels,&ap_config.channel),
|
|
ATBM_STRING_TABLE_INIT(CONF_SSID,atbm_module_config_ssids,&ap_config.ssid),
|
|
ATBM_STRING_TABLE_INIT(CONF_BSSID,atbm_module_config_macs,&ap_config.bssid),
|
|
ATBM_STRING_TABLE_INIT(CONF_PSK,atbm_module_config_ascii,&ap_config.psk),
|
|
};
|
|
|
|
if(atbm_string_parase(cmd_store,req_string,ARRAY_SIZE(req_string),select_info,len-(select_info-buf))==false){
|
|
atbm_printk_always("%s:ap config %s err\n",__func__,select_info);
|
|
res = false;
|
|
goto exit;
|
|
}
|
|
}else {
|
|
res = false;
|
|
goto exit;
|
|
}
|
|
|
|
if(ap_config.ifname.size == 0){
|
|
atbm_printk_err("%s:ifname is null\n",__func__);
|
|
res = false;
|
|
goto exit;
|
|
}
|
|
|
|
vif = atbm_module_get_sdata_by_name(ap_config.ifname.if_name);
|
|
|
|
if(vif == NULL){
|
|
atbm_printk_err("%s:[%s] not found\n",__func__,ap_config.ifname.if_name);
|
|
res = false;
|
|
goto exit;
|
|
}
|
|
|
|
if((ap_config.channel.n_channels >1) ||
|
|
(ap_config.ssid.n_ssids >1) ||
|
|
(ap_config.bssid.n_macs >1)){
|
|
atbm_printk_err("%s:config err\n",__func__);
|
|
res = false;
|
|
goto exit;
|
|
}
|
|
|
|
if((ap_config.channel.n_channels == 0)&&
|
|
(ap_config.ssid.n_ssids == 0) &&
|
|
(ap_config.bssid.n_macs == 0)){
|
|
atbm_printk_err("%s:config clear\n",__func__);
|
|
goto exit;
|
|
}
|
|
conf = &vif->ap_info;
|
|
if(ap_config.bssid.n_macs)
|
|
memcpy(conf->bssid,ap_config.bssid.mac,6);
|
|
if(ap_config.channel.n_channels)
|
|
conf->channel = ap_config.channel.channels[0];
|
|
if(ap_config.ssid.n_ssids){
|
|
conf->ssid_len = ap_config.ssid.ssids[0].ssid_len;
|
|
memcpy(conf->ssid,ap_config.ssid.ssids[0].ssid,conf->ssid_len);
|
|
}
|
|
if(ap_config.psk.len){
|
|
conf->password_len = ap_config.psk.len > 63?63:ap_config.psk.len;
|
|
memcpy(conf->password,ap_config.psk.asciis,conf->password_len);
|
|
conf->enc = true;
|
|
}else {
|
|
conf->enc = false;
|
|
}
|
|
atbm_printk_err("ap config:bssid[%pM],ssid[%s],channel[%d]\n",conf->bssid,conf->ssid,conf->channel);
|
|
exit:
|
|
rtnl_unlock();
|
|
#undef CONF_IFNAME
|
|
#undef CONF_CHANNEL
|
|
#undef CONF_SSID
|
|
#undef CONF_BSSID
|
|
if(ap_config.bssid.mac)
|
|
atbm_kfree(ap_config.bssid.mac);
|
|
if(ap_config.channel.channels)
|
|
atbm_kfree(ap_config.channel.channels);
|
|
if(ap_config.ssid.ssids)
|
|
atbm_kfree(ap_config.ssid.ssids);
|
|
if(ap_config.psk.asciis)
|
|
atbm_kfree(ap_config.psk.asciis);
|
|
rcu_assign_pointer(cmd_store->cmd_private,NULL);
|
|
return res;
|
|
}
|
|
#endif
|
|
|
|
static bool atbm_store_cmd_is_ready(struct atbm_store_cmd_code *cmd_store)
|
|
{
|
|
struct atbm_store_cmd_code *ready_cmd;
|
|
|
|
list_for_each_entry(ready_cmd, &atbm_cmd_echo_ready_list, lhead){
|
|
if((ready_cmd->label == cmd_store->label)&&
|
|
(ready_cmd->code_cmd == cmd_store->code_cmd))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
static void atbm_store_cmd_echo_done(struct atbm_store_cmd_code *cmd_store)
|
|
{
|
|
char *cmd_private;
|
|
if(cmd_store->echo_ready == false){
|
|
atbm_printk_always( "%s not in ready list\n",cmd_store->label);
|
|
WARN_ON(atbm_store_cmd_is_ready(cmd_store) == true);
|
|
}else {
|
|
list_del(&cmd_store->lhead);
|
|
ready_list_num--;
|
|
WARN_ON(ready_list_num<0);
|
|
}
|
|
cmd_private = rcu_dereference(cmd_store->cmd_private);
|
|
rcu_assign_pointer(cmd_store->cmd_private,NULL);
|
|
if(cmd_private){
|
|
synchronize_rcu();
|
|
atbm_kfree(cmd_private);
|
|
atbm_printk_always("%s:free cmd_private(%p)\n",__func__,cmd_private);
|
|
}
|
|
cmd_store->cmd_private = NULL;
|
|
cmd_store->echo_ready = false;
|
|
}
|
|
static void atbm_store_cmd_echo_ready(struct atbm_store_cmd_code *cmd_store)
|
|
{
|
|
if(cmd_store->echo_ready == true){
|
|
atbm_printk_always( "%s already in ready list\n",cmd_store->label);
|
|
WARN_ON(atbm_store_cmd_is_ready(cmd_store) == false);
|
|
return;
|
|
}
|
|
|
|
cmd_store->echo_ready = true;
|
|
|
|
if((num_echo == -1) || (num_echo>ready_list_num)){
|
|
|
|
}else if((!list_empty(&atbm_cmd_echo_ready_list))){
|
|
struct atbm_store_cmd_code *cmd_code =
|
|
list_first_entry(&atbm_cmd_echo_ready_list, struct atbm_store_cmd_code,
|
|
lhead);
|
|
if(cmd_code->show_cmd)
|
|
cmd_code->show_cmd(cmd_code,NULL,false);
|
|
atbm_store_cmd_echo_done(cmd_code);
|
|
atbm_store_cmd_deinit_show(&cmd_code->echo);
|
|
}else if(num_echo != 0){
|
|
WARN_ON(1);
|
|
}
|
|
ready_list_num ++;
|
|
list_add_tail(&cmd_store->lhead,&atbm_cmd_echo_ready_list);
|
|
}
|
|
|
|
static ssize_t atbm_module_decode_common_store(const char *buf, size_t n)
|
|
{
|
|
const char *p;
|
|
const char *code_end = NULL;
|
|
int code_len = 0;
|
|
int left_len = 0;
|
|
size_t len = n;
|
|
struct atbm_store_cmd_code *store_code;
|
|
|
|
p = atbm_skip_space(buf,n);
|
|
|
|
if(p == NULL){
|
|
atbm_printk_always("%s:all space %s\n",__func__,buf);
|
|
return -EINVAL;
|
|
}
|
|
len -= p-buf;
|
|
/*
|
|
*find the postion of cmd end,use space between tow string
|
|
*some cmd not need space ,so find enter or end of line
|
|
*/
|
|
code_end = memchr(buf, ATBM_SPACE, len);
|
|
if(code_end == NULL){
|
|
code_end = memchr(buf, ATBM_ENTER, len);
|
|
if(code_end == NULL)
|
|
code_end = memchr(buf, ATBM_LINEF, len);
|
|
}
|
|
if(code_end == NULL){
|
|
atbm_printk_always("%s:can not fine aline\n",__func__);
|
|
}
|
|
code_len = code_end ? code_end - p : len;
|
|
if(code_len<=0){
|
|
atbm_printk_always("%s code_len err\n",__func__);
|
|
return -EINVAL;
|
|
}
|
|
left_len = len - code_len;
|
|
|
|
if(left_len<0){
|
|
atbm_printk_always("%s left_len err\n",__func__);
|
|
return -EINVAL;
|
|
}
|
|
store_code = atbm_store_cmd_find_cmd(p,code_len);
|
|
|
|
if(store_code == NULL){
|
|
atbm_printk_always("%s:can not find cmd\n",__func__);
|
|
return -EINVAL;
|
|
}
|
|
BUG_ON(store_code->code_cmd == NULL);
|
|
|
|
p = atbm_skip_space(code_end,left_len);
|
|
if(p == NULL){
|
|
left_len = 0;
|
|
}else {
|
|
left_len -= p-code_end;
|
|
}
|
|
if(left_len<0){
|
|
atbm_printk_always("%s left_len err,params err\n",__func__);
|
|
return -EINVAL;
|
|
}
|
|
if(atbm_store_cmd_init_show(&store_code->echo) == false){
|
|
atbm_printk_always("%s show buff init err\n",__func__);
|
|
return -EINVAL;
|
|
}
|
|
/*
|
|
*set default enable_echo
|
|
*/
|
|
store_code->echo_enable = enable_echo;
|
|
|
|
if(store_code->code_cmd(store_code,p,left_len) == true){
|
|
if(store_code->echo_enable == true){
|
|
atbm_module_show_put(&store_code->echo,"%s[%s]\n",store_code->label,"OK");
|
|
atbm_store_cmd_echo_ready(store_code);
|
|
}else{
|
|
if(store_code->show_cmd)
|
|
store_code->show_cmd(store_code,NULL,false);
|
|
atbm_store_cmd_echo_done(store_code);
|
|
atbm_store_cmd_deinit_show(&store_code->echo);
|
|
}
|
|
}else {
|
|
if(store_code->echo_enable == true){
|
|
atbm_module_show_put(&store_code->echo,"%s[%s]\n",store_code->label,"ERR");
|
|
}
|
|
atbm_store_cmd_echo_done(store_code);
|
|
atbm_store_cmd_deinit_show(&store_code->echo);
|
|
|
|
return -EINVAL;
|
|
}
|
|
return n;
|
|
}
|
|
static ssize_t atbm_module_cmd_store(struct kobject *kobj, struct kobj_attribute *attr,
|
|
const char *buf, size_t n)
|
|
{
|
|
ssize_t mg_size = 0;
|
|
atbm_modulefs_lock();
|
|
atbm_module_muxlock();
|
|
mg_size = atbm_module_decode_common_store(buf,n);
|
|
atbm_module_muxunlock();
|
|
atbm_modulefs_unlock();
|
|
return mg_size;
|
|
}
|
|
static ssize_t atbm_module_cmd_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
ssize_t len = 0;
|
|
u8* show_buff = NULL;
|
|
ssize_t show_len = 0;
|
|
atbm_modulefs_lock();
|
|
atbm_module_muxlock();
|
|
show_buff = atbm_kzalloc(ATBM_SHOW_MSG_MAX_SIZE, GFP_KERNEL);
|
|
while (!list_empty(&atbm_cmd_echo_ready_list)) {
|
|
struct atbm_store_cmd_code *cmd_code =
|
|
list_first_entry(&atbm_cmd_echo_ready_list, struct atbm_store_cmd_code,
|
|
lhead);
|
|
|
|
if(cmd_code->show_cmd)
|
|
show_len = cmd_code->show_cmd(cmd_code,show_buff,show_buff ? true:false);
|
|
if(show_buff){
|
|
if((show_len)&&(len+show_len<ATBM_SHOW_MSG_MAX_SIZE)){
|
|
memcpy(buf+len,show_buff,show_len);
|
|
len += show_len;
|
|
}
|
|
}
|
|
show_len = 0;
|
|
atbm_store_cmd_echo_done(cmd_code);
|
|
atbm_store_cmd_deinit_show(&cmd_code->echo);
|
|
}
|
|
if(len&&show_buff){
|
|
if(WARN_ON(len>ATBM_SHOW_MSG_MAX_SIZE))
|
|
len = ATBM_SHOW_MSG_MAX_SIZE;
|
|
memset(backup_show,0,ATBM_SHOW_MSG_MAX_SIZE);
|
|
memcpy(backup_show,show_buff,len);
|
|
backup_show_size = len;
|
|
}
|
|
atbm_module_muxunlock();
|
|
atbm_modulefs_unlock();
|
|
if(show_buff)
|
|
atbm_kfree(show_buff);
|
|
return len;
|
|
}
|
|
|
|
static void atbm_module_cmd_init(void)
|
|
{
|
|
unsigned int index = 0;
|
|
|
|
INIT_LIST_HEAD(&atbm_cmd_echo_ready_list);
|
|
atbm_common_hash_list_init(atbm_cmd_hash_head,ATBM_CMD_HASHENTRIES);
|
|
|
|
for(index = 0;index<ARRAY_SIZE(cmd_code_buff);index++){
|
|
unsigned int hash_index = atbm_hash_index(cmd_code_buff[index].label,
|
|
strlen(cmd_code_buff[index].label),ATBM_CMD_HASHBITS);
|
|
BUG_ON(strlen(cmd_code_buff[index].label) > ATBM_CMD_MAX_STRING_LEN);
|
|
hlist_add_head(&cmd_code_buff[index].hnode,&atbm_cmd_hash_head[hash_index]);
|
|
cmd_code_buff[index].echo_ready = false;
|
|
atbm_store_cmd_deinit_show(&cmd_code_buff[index].echo);
|
|
atbm_printk_debug("%s:[%s]->[%d]\n",__func__,cmd_code_buff[index].label,hash_index);
|
|
}
|
|
|
|
backup_show = atbm_kzalloc(ATBM_SHOW_MSG_MAX_SIZE, GFP_KERNEL);
|
|
WARN_ON(backup_show == NULL);
|
|
backup_show_size = 0;
|
|
}
|
|
|
|
static void atbm_module_cmd_exit(void)
|
|
{
|
|
while (!list_empty(&atbm_cmd_echo_ready_list)) {
|
|
struct atbm_store_cmd_code *cmd_code =
|
|
list_first_entry(&atbm_cmd_echo_ready_list, struct atbm_store_cmd_code,
|
|
lhead);
|
|
if(cmd_code->show_cmd)
|
|
cmd_code->show_cmd(cmd_code,NULL,false);
|
|
atbm_store_cmd_echo_done(cmd_code);
|
|
atbm_store_cmd_deinit_show(&cmd_code->echo);
|
|
}
|
|
|
|
if(backup_show){
|
|
atbm_kfree(backup_show);
|
|
}
|
|
backup_show = NULL;
|
|
backup_show_size = 0;
|
|
}
|
|
static void atbm_module_firmware_caps_show(struct atbm_module_show *show_buff,struct atbm_common *hw_priv)
|
|
{
|
|
#define WSM_CAP(cap) !!(hw_priv->wsm_caps.firmwareCap&cap)
|
|
|
|
atbm_module_show_put(show_buff,LIGHT"Firmare Cap:"NORMAL ENTER);
|
|
atbm_module_show_put(show_buff,"PRIVATE_IE [%d]\n" ,WSM_CAP(CAPABILITIES_ATBM_PRIVATE_IE));
|
|
atbm_module_show_put(show_buff,"NVR_IPC [%d]\n" ,WSM_CAP(CAPABILITIES_NVR_IPC));
|
|
atbm_module_show_put(show_buff,"NO_CONFIRM [%d]\n" ,WSM_CAP(CAPABILITIES_NO_CONFIRM));
|
|
atbm_module_show_put(show_buff,"SDIO_PATCH [%d]\n" ,WSM_CAP(CAPABILITIES_SDIO_PATCH));
|
|
atbm_module_show_put(show_buff,"NO_BACKOFF [%d]\n" ,WSM_CAP(CAPABILITIES_NO_BACKOFF));
|
|
atbm_module_show_put(show_buff,"CFO [%d]\n" ,WSM_CAP(CAPABILITIES_CFO));
|
|
atbm_module_show_put(show_buff,"AGC [%d]\n" ,WSM_CAP(CAPABILITIES_AGC));
|
|
atbm_module_show_put(show_buff,"TXCAL [%d]\n" ,WSM_CAP(CAPABILITIES_TXCAL));
|
|
atbm_module_show_put(show_buff,"CTS_BUG [%d]\n" ,WSM_CAP(CAPABILITIES_CTS_BUG));
|
|
atbm_module_show_put(show_buff,"MONITOR [%d]\n" ,WSM_CAP(CAPABILITIES_MONITOR));
|
|
atbm_module_show_put(show_buff,"CUSTOM [%d]\n" ,WSM_CAP(CAPABILITIES_CUSTOM));
|
|
atbm_module_show_put(show_buff,"SMARTCONFIG [%d]\n" ,WSM_CAP(CAPABILITIES_SMARTCONFIG));
|
|
atbm_module_show_put(show_buff,"ETF [%d]\n" ,WSM_CAP(CAPABILITIES_ETF));
|
|
atbm_module_show_put(show_buff,"LMAC_RATECTL[%d]\n" ,WSM_CAP(CAPABILITIES_LMAC_RATECTL));
|
|
atbm_module_show_put(show_buff,"LMAC_TPC [%d]\n" ,WSM_CAP(CAPABILITIES_LMAC_TPC));
|
|
atbm_module_show_put(show_buff,"LMAC_TEMPC [%d]\n" ,WSM_CAP(CAPABILITIES_LMAC_TEMPC));
|
|
atbm_module_show_put(show_buff,"USE_IPC [%d]\n" ,WSM_CAP(CAPABILITIES_USE_IPC));
|
|
atbm_module_show_put(show_buff,"OUTER_PA [%d]\n" ,WSM_CAP(CAPABILITIES_OUTER_PA));
|
|
atbm_module_show_put(show_buff,"HW_CHECKSUM [%d]\n" ,WSM_CAP(CAPABILITIES_HW_CHECKSUM));
|
|
atbm_module_show_put(show_buff,"MULTI_RX [%d]\n" ,WSM_CAP(CAPABILITIES_SINGLE_CHANNEL_MULTI_RX));
|
|
atbm_module_show_put(show_buff,"USB_RECOVERY_BUG [%d]\n" ,WSM_CAP(CAPABILITIES_USB_RECOVERY_BUG));
|
|
atbm_module_show_put(show_buff,"POWER_CONSUMPTION [%d]\n" ,WSM_CAP(CAPABILITIES_POWER_CONSUMPTION));
|
|
atbm_module_show_put(show_buff,"RSSI_DECIDE_TXPOWER [%d]\n" ,WSM_CAP(CAPABILITIES_RSSI_DECIDE_TXPOWER));
|
|
atbm_module_show_put(show_buff,"RTS_LONG_DUR [%d]\n" ,WSM_CAP(CAPABILITIES_RTS_LONG_DURATION));
|
|
atbm_module_show_put(show_buff,"TX_CFO_PPM_CORRECTION [%d]\n" ,WSM_CAP(CAPABILITIES_TX_CFO_PPM_CORRECTION));
|
|
atbm_module_show_put(show_buff,"NOISE_SET_DCXO [%d]\n" ,WSM_CAP(CAPABILITIES_NOISE_SET_DCXO));
|
|
}
|
|
|
|
static void atbm_module_driver_caps_show(struct atbm_module_show *show_buff,struct atbm_common *hw_priv)
|
|
{
|
|
atbm_module_show_put(show_buff,LIGHT"Driver Cap:"NORMAL ENTER);
|
|
#ifdef USB_BUS
|
|
atbm_module_show_put(show_buff,"HIF_TYPE [%s]\n","USB");
|
|
#endif
|
|
#ifdef SDIO_BUS
|
|
atbm_module_show_put(show_buff,"HIF_TYPE [%s]\n","SDIO");
|
|
#endif
|
|
#ifdef SPI_BUS
|
|
atbm_module_show_put(show_buff,"HIF_TYPE [%s]\n","SPI");
|
|
#endif
|
|
#ifdef ATBM_NOT_SUPPORT_40M_CHW
|
|
atbm_module_show_put(show_buff,"HW_CHW [%s]\n","40M");
|
|
#else
|
|
atbm_module_show_put(show_buff,"HW_CHW [%s]\n","20M");
|
|
#endif
|
|
#ifdef CONFIG_ATBM_5G_PRETEND_2G
|
|
atbm_module_show_put(show_buff,"BAND_SUPPORT[%s]\n","5G and 2G");
|
|
#else
|
|
atbm_module_show_put(show_buff,"BAND_SUPPORT[%s]\n","only 2G");
|
|
#endif
|
|
|
|
}
|
|
static ssize_t atbm_module_show_system_info(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
struct atbm_module_show sys_show;
|
|
struct atbm_common *hw_priv = NULL;
|
|
|
|
atbm_show_init(&sys_show,buf);
|
|
|
|
atbm_module_muxlock();
|
|
if(atbm_hw_priv_dereference() == NULL){
|
|
atbm_module_show_put(&sys_show,"system info not exit,please plug chip\n");
|
|
goto exit;
|
|
}
|
|
hw_priv = atbm_hw_priv_dereference();
|
|
atbm_module_show_put(&sys_show,LIGHT"DriverVer [%d]"NORMAL ENTER ,DRIVER_VER);
|
|
atbm_module_show_put(&sys_show,LIGHT"FirmwareVer [%d]"NORMAL ENTER ,hw_priv->wsm_caps.firmwareVersion);
|
|
atbm_module_firmware_caps_show(&sys_show,hw_priv);
|
|
atbm_module_driver_caps_show(&sys_show,hw_priv);
|
|
exit:
|
|
atbm_module_muxunlock();
|
|
|
|
return sys_show.show_count;
|
|
}
|
|
static ssize_t atbm_module_show_backup_info(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
{
|
|
ssize_t size = 0;
|
|
|
|
atbm_modulefs_lock();
|
|
atbm_module_muxlock();
|
|
if(backup_show && backup_show_size){
|
|
size = backup_show_size;
|
|
if(WARN_ON(size > ATBM_SHOW_MSG_MAX_SIZE))
|
|
size = ATBM_SHOW_MSG_MAX_SIZE;
|
|
memcpy(buf,backup_show,ATBM_SHOW_MSG_MAX_SIZE);
|
|
}
|
|
atbm_module_muxunlock();
|
|
atbm_modulefs_unlock();
|
|
|
|
return size;
|
|
}
|
|
static struct kobject *atbm_module_kobj = NULL;
|
|
|
|
static struct kobj_attribute atbm_module_common_attr = __ATTR(atbm_cmd, 0644,atbm_module_cmd_show,atbm_module_cmd_store);
|
|
static struct kobj_attribute atbm_module_sysinfo_attr = __ATTR(atbm_sys, 0444,atbm_module_show_system_info, NULL);
|
|
static struct kobj_attribute atbm_module_common_backup_attr = __ATTR(atbm_sys_backup, 0444,atbm_module_show_backup_info, NULL);
|
|
|
|
static struct attribute *atbm_module_attribute_group[]= {
|
|
&atbm_module_common_attr.attr,
|
|
&atbm_module_common_backup_attr.attr,
|
|
&atbm_module_sysinfo_attr.attr,
|
|
NULL,
|
|
};
|
|
static struct attribute_group atbm_module_attr_group = {
|
|
.attrs = atbm_module_attribute_group,
|
|
};
|
|
|
|
int atbm_module_attribute_init(void)
|
|
{
|
|
int error;
|
|
struct kobject *parent = atbm_module_parent;
|
|
|
|
atbm_module_kobj = kobject_create_and_add("atbmfs",parent);
|
|
if (!atbm_module_kobj){
|
|
return -EINVAL;
|
|
}
|
|
error = sysfs_create_group(atbm_module_kobj, &atbm_module_attr_group);
|
|
if (error)
|
|
kobject_put(atbm_module_kobj);
|
|
atbm_modulefs_lock_int();
|
|
atbm_module_cmd_init();
|
|
return error;
|
|
}
|
|
void atbm_module_attribute_exit(void)
|
|
{
|
|
if(atbm_module_kobj == NULL)
|
|
return;
|
|
sysfs_remove_group(atbm_module_kobj, &atbm_module_attr_group);
|
|
kobject_put(atbm_module_kobj);
|
|
atbm_modulefs_lock();
|
|
atbm_module_cmd_exit();
|
|
atbm_modulefs_unlock();
|
|
atbm_modulefs_lock_release();
|
|
}
|