#include <unistd.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <linux/socket.h>
#include <netpacket/packet.h>
#include <net/if.h>
#include <errno.h>
#include <arpa/inet.h>
#define CMD_WOWL_EXTGPIO "dhd_priv wl wowl_extgpio 1"
#define CMD_WOWL_GPIO "dhd_priv wl wowl_gpio 2"
#define CMD_WOWL_WAKEIND "dhd_priv wl wowl_wakeind"
#define CMD_WOWL_WAKEIND_CLR "dhd_priv wl wowl_wakeind clear"
#define CMD_WOWL "dhd_priv wl wowl 0x16"
#define CMD_TCPKA_CONN_SESS_INFO "dhd_priv wl tcpka_conn_sess_info 1"
#define CMD_TCPKA_CONN_DUMP_0 "dhd_priv wl tcpka_conn_dump 0"
#define CMD_TCPKA_CONN_DUMP_1 "dhd_priv wl tcpka_conn_dump 1"
#define CMD_WOWL_PATTERN_CLR "dhd_priv wl wowl_pattern clr"
#define CMD_WOWL_ACTIVATE "dhd_priv wl wowl_activate 1"
#define CMD_SETSUSPENDMODE_1 "dhd_priv setsuspendmode 1"
#define CMD_SETSUSPENDMODE_0 "dhd_priv setsuspendmode 0"
#define CMD_TCPKA_CONN_ENABLE_CLR "dhd_priv wl tcpka_conn_enable 1 0 0 0 0"
#define CMD_TCPKA_CONN_DEL "dhd_priv wl tcpka_conn_del 1"
#define DEFAULT_WL_TCPKA_CONN_ADD "dhd_priv wl tcpka_conn_add 1"
#define DEFAULT_WL_TCPKA_CONN_ENABLE "dhd_priv wl tcpka_conn_enable 1 1"
#define DEFAULT_LAST_KA_PAYLOAD_LEN "5"
#define MS 1000
#define BUFLENGTH (256 * sizeof(char))
#define IP_SIZE 16
#define DEFAULT_IFNAME "wlan0"
#define DEFAULT_IPID "1"
#define DEFAULT_SEQ "1"
#define DEFAULT_WIN_TSVAR_TSECR "1 1 1"
#define RETRY 5
#define TCPKA_SENDPKT_FAILED -100
//#define LENGTH (sizeof(DEFAULT_WL_TCPKA_CONN_ADD)+IP_SIZE + sizeof(DEFAULT_IPID) + sizeof(DEFAULT_SEQ) + sizeof(DEFAULT_WIN_TSVAR_TSECR)-4)
enum {
STEP_WOWL_EXTGPIO = 0,
STEP_WOWL_GPIO,
STEP_WOWL_WAKEIND_0,
STEP_WOWL_WAKEIND_CLR,
STEP_WOWL,
STEP_TCPKA_CONN_ADD,
STEP_TCPKA_CONN_SESS_INFO_0,
STEP_TCPKA_CONN_DUMP_1,
/*send a packet here*/
STEP_TCPKA_CONN_SESS_INFO_1,
STEP_TCPKA_CONN_DUMP_0,
STEP_TCPKA_CONN_ENABLE,
//STEP_WOWL_PATTERN_CLR,
//STEP_WOWL_PATTERN_ADD,
//STEP_WOWL_ACTIVATE,
SETP_SETSUSPENDMODE_1,
SETP_SETSUSPENDMODE_0,
STEP_WOWL_WAKEIND_1,
STEP_TCPKA_CONN_ENABLE_CLR,
STEP_TCPKA_CONN_DEL,
};
enum {
TCPKA_DST_MAC = 1,
TCPKA_DST_IPADDR,
TCPKA_SRC_PORT,
TCPKA_DST_PORT,
TCPKA_ACK,
TCPKA_INTERVAL,
TCPKA_RETRY_INTERVAL,
TCPKA_RETRY_COUNT,
TCPKA_PARAMS_TOTAL,
};
typedef struct demo_do_tcpka_cmd{
int const step;
int delay;
char *wlcmd;
}demo_do_tcpka_cmd;
int demo_check_params(char **params,int *lenTcpKaAddBuf,int *lenTcpKaEnableBuf)
{
int length = 0,i = 0;
struct demo_tcpka_params{
int const num;
int const size;
const char *param;
}tcpka_params[TCPKA_PARAMS_TOTAL]={
{0,0,NULL},
{TCPKA_DST_MAC,17,params[TCPKA_DST_MAC]},
{TCPKA_DST_IPADDR,15,params[TCPKA_DST_IPADDR]},
{TCPKA_SRC_PORT,5,params[TCPKA_SRC_PORT]},
{TCPKA_DST_PORT,5,params[TCPKA_DST_PORT]},
{TCPKA_ACK,1,params[TCPKA_ACK]},
{TCPKA_INTERVAL,4,params[TCPKA_INTERVAL]},
{TCPKA_RETRY_INTERVAL,4,params[TCPKA_RETRY_INTERVAL]},
{TCPKA_RETRY_COUNT,4,params[TCPKA_RETRY_COUNT]},
};
if(strlen(tcpka_params[TCPKA_DST_MAC].param) != 17)
return -1;
for(i=TCPKA_DST_MAC;i <= TCPKA_ACK;i++)
{
if((length = strlen(tcpka_params[i].param)) > tcpka_params[i].size)
return -1;
else *lenTcpKaAddBuf += length;
}
length = 0;
for(i=TCPKA_INTERVAL;i <= TCPKA_RETRY_COUNT;i++)
if((length = strlen(tcpka_params[i].param)) > tcpka_params[i].size)
return -1;
else *lenTcpKaEnableBuf += length;
return 0;
}
int demo_get_localip(const char *eth_inf, char *ip,int sockfd)
{
int ret = -1;
struct sockaddr_in sin;
struct ifreq ifr;
strncpy(ifr.ifr_name, eth_inf, IFNAMSIZ);
ifr.ifr_name[IFNAMSIZ - 1] = 0;
ret = ioctl(sockfd, SIOCGIFADDR, &ifr);
if(ret < 0)
{
printf("ioctl error: %s\n", strerror(errno));
ret = -1;
return ret;
}
memcpy(&sin, &ifr.ifr_addr, sizeof(sin));
snprintf(ip, IP_SIZE, "%s", inet_ntoa(sin.sin_addr));
return ret;
}
int demo_do_cpy(char *dst,const char *src,int offset,int length)
{
int len = strlen(src);
if(offset + len > length -1) /*1 byte for ' '*/
return (int)-BUFLENGTH;
memcpy(dst,src,len);
dst[len] = ' ';
return len+1;
}
int demo_get_tcpka_string(char *TcpKaAddBuf,char *TcpKaEnableBuf,char *IPBuf,unsigned char *ConvertData,char **src,int lenTcpKaAddBuf,int lenTcpKaEnableBuf)
{
/* wl tcpka_conn_add 1 08:9B:4B:B6:FE:A4 192.168.2.124 192.168.1.103 1 9000 8000 123 1 0 0 0 5 0x341254455354000028032320*/
int offset = 0, i = 0,j = 1;
char *srctmp = NULL;
for(i = 0;i < 12;i++)
{
if(i == 0)
srctmp = DEFAULT_WL_TCPKA_CONN_ADD;
else if(i == 2)
srctmp = IPBuf;
else if(i == 4)
srctmp = DEFAULT_IPID;
else if(i == 7)
srctmp = DEFAULT_SEQ;
else if(i == 9)
srctmp = DEFAULT_WIN_TSVAR_TSECR;
else if(i == 10)
srctmp = DEFAULT_LAST_KA_PAYLOAD_LEN;
else if(i == 11)
srctmp = ConvertData;
else{
srctmp = src[j];
j++;
}
offset += demo_do_cpy(TcpKaAddBuf + offset ,srctmp,offset,lenTcpKaAddBuf);
if(offset <= 0)
break;
}
if(offset > 0){
TcpKaAddBuf[offset-1] = '\0';
offset = 0;
}
else{
memset(TcpKaAddBuf,0,lenTcpKaAddBuf);
return offset;
}
for(i = 0;i < 4;i++)
{
if(i == 0)
srctmp = DEFAULT_WL_TCPKA_CONN_ENABLE;
else{
srctmp = src[j];
j++;
}
offset += demo_do_cpy(TcpKaEnableBuf + offset ,srctmp,offset,lenTcpKaEnableBuf);
if(offset <= 0)
break;
}
if(offset > 0){
TcpKaEnableBuf[offset-1] = '\0';
offset = 0;
}
else{
memset(TcpKaEnableBuf,0,lenTcpKaEnableBuf);
return offset;
}
return 0;
}
//example to get a tcpka ascill from data:
int demo_data_to_ascill(unsigned char *dst,void *src,int length)
{
int i = 0;
char *srctmp = (char *)src;
char *dsttmp = dst;
if(!dst || !src || length < 0)
return -1;
snprintf(dsttmp,3,"%s","0x");
dsttmp += 2;
for(i=0;i < length;i++)
{
snprintf(dsttmp,3,"%02hhx",*srctmp);
dsttmp += 2;
srctmp += 1;
}
if(strlen(dst) > 2){
//printf("demo_data_to_ascill %s i=%d length=%d sizeof=%d\n",dst,i,length,strlen(dst));
}
return 0;
}
//example to get a tcpka ascill from data:
int main(int argc,char **argv)
{
int ret = -1,i = 0,lenTcpKaAddBuf = 0,lenTcpKaEnableBuf = 0,lenNoPayload = 0;
char *TcpKaAddBuf = NULL, *TcpKaEnableBuf = NULL, *IPBuf = NULL;
unsigned char *ConvertData = NULL;
demo_do_tcpka_cmd do_tcpka_cmd[]={
{STEP_WOWL_EXTGPIO, MS, CMD_WOWL_EXTGPIO},
{STEP_WOWL_GPIO, MS, CMD_WOWL_GPIO},
{STEP_WOWL_WAKEIND_0, MS, CMD_WOWL_WAKEIND},
{STEP_WOWL_WAKEIND_CLR, MS, CMD_WOWL_WAKEIND_CLR},
{STEP_WOWL, MS, CMD_WOWL},
{STEP_TCPKA_CONN_ADD, MS*300, NULL},
{STEP_TCPKA_CONN_SESS_INFO_0, MS, CMD_TCPKA_CONN_SESS_INFO},
{STEP_TCPKA_CONN_DUMP_1, MS*100, CMD_TCPKA_CONN_DUMP_1},
{STEP_TCPKA_CONN_SESS_INFO_1, MS, CMD_TCPKA_CONN_SESS_INFO},
{STEP_TCPKA_CONN_DUMP_0, MS, CMD_TCPKA_CONN_DUMP_0},
{STEP_TCPKA_CONN_ENABLE, MS, NULL},
//{STEP_WOWL_PATTERN_CLR, MS, CMD_WOWL_PATTERN_CLR},
//{STEP_WOWL_PATTERN_ADD, MS*100, CMD_WOWL_PATTERN_ADD},
//{STEP_WOWL_ACTIVATE, MS, CMD_WOWL_ACTIVATE},
{SETP_SETSUSPENDMODE_1, MS, CMD_SETSUSPENDMODE_1},
//{SETP_SETSUSPENDMODE_0, MS, CMD_SETSUSPENDMODE_0},
{STEP_WOWL_WAKEIND_1, MS, CMD_WOWL_WAKEIND},
{STEP_TCPKA_CONN_ENABLE_CLR, MS, CMD_TCPKA_CONN_ENABLE_CLR},
{STEP_TCPKA_CONN_DEL, MS, CMD_TCPKA_CONN_DEL},
};
struct tcpka_payload {
const unsigned short int id;
const unsigned char name[6];
const unsigned int SN;
}tcpka_payload =
{
.SN = 0x20230328,
.id = 0x1234,
.name = {"TCPKA"},
};
if (argc < 9) {
printf("DST_MAC:[08:9B:4B:B6:FE:A4]\n DST_IPADDR:[192.168.2.124]\n SRC_PORT:[9000]\n DST_PORT:[8000]\n ACK:[0 or 1] while '0' will do offload tcp connect,'1' will based on host tcp connect\n TCPKA_INTERVAL:[5]\n TCPKA_RETRY_INTERVAL:[1]\n TCPKA_RETRY_COUNT:[5]\n");
printf("Total run cmd: ./tcpka 08:9B:4B:B6:FE:A4 192.168.1.103 9000 8000 1 5 1 5\n");
return -1;
}
ret = demo_check_params(argv,&lenTcpKaAddBuf,&lenTcpKaEnableBuf);
if(ret < 0)
{
printf("params may not suitable \n");
return ret;
}
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0)
{
printf("socket error, exit\n");
return -1;
}
if(!strcmp(argv[TCPKA_ACK],"0")){
printf("offload creat connect Enabled\n");
//goto fw_auto_creat_conn;
}
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_addr = INADDR_ANY,
.sin_port = htons(atoi(argv[TCPKA_SRC_PORT])),
};
ret = bind(sockfd, (const struct sockaddr *) &addr, sizeof(addr));
if (ret < 0) {
printf("bind failed\n");
return ret;
}
addr.sin_addr.s_addr = inet_addr(argv[TCPKA_DST_IPADDR]);
addr.sin_port = htons(atoi(argv[TCPKA_DST_PORT]));
ret = connect(sockfd, (const struct sockaddr *) &addr, sizeof(addr));
if (ret < 0) {
printf("connect failed\n");
return ret;
}
//just do a send test,don't care about success or failed!
ret = send(sockfd, &tcpka_payload, sizeof(tcpka_payload), 0);
IPBuf=(char*) malloc(IP_SIZE);
if(IPBuf)
memset(IPBuf,0,IP_SIZE);
else
goto exit;
ret = demo_get_localip(DEFAULT_IFNAME,IPBuf,sockfd);
if(ret < 0)
{
printf("demo_get_localip failed,exit");
goto exit;
}
/**5 bytes for 5 strlen(argv[params]**/
lenNoPayload = lenTcpKaAddBuf + sizeof(DEFAULT_WL_TCPKA_CONN_ADD) + strlen(IPBuf) + 1 + sizeof(DEFAULT_LAST_KA_PAYLOAD_LEN) + sizeof(DEFAULT_IPID)+ sizeof(DEFAULT_SEQ) + sizeof(DEFAULT_WIN_TSVAR_TSECR) + 5;
/*1 char [FF] needed 2 bytes for HEX Convert, 1 byte for '\0', 2 byte for "0x" */
if(BUFLENGTH-lenNoPayload < sizeof(tcpka_payload) * 2 + 1 + 2)
{
printf("TCPKA PAYLOAD should be less than %d bytes\n",(BUFLENGTH-lenNoPayload-3) / 2);
goto exit;
}
ConvertData=(unsigned char *) malloc(sizeof(tcpka_payload) * 2 + 1 + 2);
if(ConvertData)
memset(ConvertData,0,sizeof(tcpka_payload) * 2 + 1 + 2);
else
goto exit;
ret = demo_data_to_ascill(ConvertData,&tcpka_payload,sizeof(tcpka_payload));
if(ret < 0)
{
printf("demo_data_to_ascill failed\n");
goto exit;
}
/* wl tcpka_conn_add 1 08:9B:4B:B6:FE:A4 192.168.2.124 192.168.1.103 1 9000 8000 123 1 0 0 0 5 0x341254455354000028032320*/
lenTcpKaAddBuf = strlen(ConvertData) + 1 + lenNoPayload; //1 byte for '\0'
if(lenTcpKaAddBuf > BUFLENGTH)
goto exit;
TcpKaAddBuf=(char*) malloc(lenTcpKaAddBuf);
if(TcpKaAddBuf)
memset(TcpKaAddBuf,0,lenTcpKaAddBuf);
else
goto exit;
lenTcpKaEnableBuf += sizeof(DEFAULT_WL_TCPKA_CONN_ENABLE) + 3; //3 bytes for 3 strlen(argv[params])
if(lenTcpKaEnableBuf > BUFLENGTH)
goto exit;
TcpKaEnableBuf=(char*) malloc(lenTcpKaEnableBuf);
if(TcpKaEnableBuf)
memset(TcpKaEnableBuf,0,lenTcpKaEnableBuf);
else
goto exit;
ret = demo_get_tcpka_string(TcpKaAddBuf,TcpKaEnableBuf,IPBuf,ConvertData,argv,lenTcpKaAddBuf,lenTcpKaEnableBuf);
if(ret < 0)
{
printf("demo_get_tcpka_string failed\n");
ret = -1;
goto exit;
}
if((lenTcpKaAddBuf = strlen(TcpKaAddBuf) )&& (lenTcpKaEnableBuf = strlen(TcpKaEnableBuf)))
printf("%s %d\n%s %d\n",TcpKaAddBuf,lenTcpKaAddBuf,TcpKaEnableBuf,lenTcpKaEnableBuf);
else goto exit;
do_tcpka_cmd[STEP_TCPKA_CONN_ADD].wlcmd = TcpKaAddBuf;
do_tcpka_cmd[STEP_TCPKA_CONN_ENABLE].wlcmd = TcpKaEnableBuf;
for(i = STEP_TCPKA_CONN_ADD;i <= SETP_SETSUSPENDMODE_1; i++){
if(do_tcpka_cmd[i].wlcmd)
ret = system(do_tcpka_cmd[i].wlcmd);
if(ret < 0)
{
printf("issue dhd_priv cmd failed,exit\n");
goto exit_tcpka_add_failed;
}
if(do_tcpka_cmd[i].delay)
usleep(do_tcpka_cmd[i].delay);
if(do_tcpka_cmd[i].step == STEP_TCPKA_CONN_DUMP_1 && strcmp(argv[TCPKA_ACK],"0")){
int retry = RETRY;
do {
if(send(sockfd, &tcpka_payload, sizeof(tcpka_payload), 0) == sizeof(tcpka_payload))
break;
}while(retry--);
if(retry <= 0){
ret = TCPKA_SENDPKT_FAILED;
goto exit_tcpka_add_failed;
}
}
}
//the dhd driver suspend after the last cmd.
sleep(10);
printf("tcpka setup already finished\n");
// printf("10 sleep test ,wait for sleep 13s\n");
//now resume the dhd driver
//for(i = SETP_SETSUSPENDMODE_0;i <= STEP_TCPKA_CONN_DEL;i++){
// system(do_tcpka_cmd[i].wlcmd);
// if(do_tcpka_cmd[i].delay)
// usleep(do_tcpka_cmd[i].delay);
//}
// replay the dhd driver suspend after the last cmd.
#if 0
for(i = 0;i <= SETP_SETSUSPENDMODE_1;i++){
system(do_tcpka_cmd[i].wlcmd);
if(do_tcpka_cmd[i].step == STEP_TCPKA_CONN_DUMP_1 && strcmp(argv[TCPKA_ACK],"0"))
send(sockfd, "tcpka", 5, 0);
if(do_tcpka_cmd[i].delay)
usleep(do_tcpka_cmd[i].delay);
}
#endif
//while(1);
exit_tcpka_add_failed:
if(TCPKA_SENDPKT_FAILED == ret)
{
system(do_tcpka_cmd[STEP_TCPKA_CONN_DUMP_0].wlcmd);
system(do_tcpka_cmd[STEP_TCPKA_CONN_DEL].wlcmd);
printf("send pkt failed,exit\n");
}
exit:
if(IPBuf){
free(IPBuf);
IPBuf = NULL;
}
if(TcpKaAddBuf){
free(TcpKaAddBuf);
TcpKaAddBuf = NULL;
}
if(TcpKaEnableBuf){
free(TcpKaEnableBuf);
TcpKaEnableBuf = NULL;
}
if(ConvertData){
free(ConvertData);
ConvertData = NULL;
}
close(sockfd);
return ret;
}