blob: 808ab83ce5774fa47fb871f4c3b72fdbd9ae563e [file] [edit]
/****************************************************************************
*
* Copyright (c) 2016 Wi-Fi Alliance
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
* USE OR PERFORMANCE OF THIS SOFTWARE.
*
*****************************************************************************/
#include <ctype.h>
#include <sys/types.h>
#include <sys/time.h>
#include <stdio.h>
#include <signal.h>
#include <sys/socket.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <rpc/rpc.h>
#include <linux/ip.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include "wfa_con.h"
unsigned int rmsg[512]; // rx msg buffer
unsigned int txmsg[512]; // tx msg buffer
struct itimerval waitval_state = { 40,0};
#define PORT 12345 // port for sending/receiving
#define MAXRETRY 3 // port for sending/receiving
#define SLEEP_PERIOD 10 //time to exit itself
#define INTERSTEP_PERIOD 5 //time allowed within steps
int port = PORT;
int reset = 0;
int tout = 0;
int reset_recd = 0;
int num_retry = 0;
int tos_vo,tos_vi,tos_be,tos_bk;
int timeron=SLEEP_PERIOD;
int exitflag=0;
pthread_t time_thr;
struct apts_msg apts_msgs[] =
{
{0, -1},
{"B.D", B_D},
{"B.H", B_H},
{"B.B", B_B},
{"B.M", B_M},
{"M.D", M_D},
{"B.Z", B_Z},
{"M.Y", M_Y},
{"L.1", L_1},
{"A.Y", A_Y},
{"B.W", B_W},
{"A.J", A_J},
{"M.V", M_V},
{"M.U", M_U},
{"A.U", A_U},
{"M.L", M_L},
{"B.K", B_K},
{"M.B", M_B},
{"M.K", M_K},
{"M.W", M_W},
{"APTS TX ", APTS_DEFAULT },
{"APTS Hello ", APTS_HELLO },
{"APTS Broadcast ", APTS_BCST },
{"APTS Confirm ", APTS_CONFIRM},
{"APTS STOP ", APTS_STOP},
{"APTS CK BE ", APTS_CK_BE },
{"APTS CK BK ", APTS_CK_BK },
{"APTS CK VI ", APTS_CK_VI },
{"APTS CK VO ", APTS_CK_VO },
{"APTS RESET ", APTS_RESET },
{"APTS RESET RESP ", APTS_RESET_RESP },
{"APTS RESET STOP ", APTS_RESET_STOP },
{0, 0 } // APTS_LAST
};
struct station;
int WfaConRcvHello(struct station *,unsigned int *,int );
int WfaConRcvConf(struct station *,unsigned int *,int );
int WfaConRcvVOSnd(struct station *,unsigned int *,int );
int WfaConRcvVOSndCyclic(struct station *,unsigned int *,int );
int WfaConRcvVOSndE(struct station *,unsigned int *,int );
int WfaConRcvVOE(struct station *,unsigned int *,int );
int WfaConWaitStop(struct station *,unsigned int *,int );
int WfaConRcvVOSnd2VO(struct station *,unsigned int *,int );
int WfaConRcvVO(struct station *,unsigned int *,int );
int WfaConRcvVI(struct station *,unsigned int *,int );
int WfaConRcvBE(struct station *,unsigned int *,int );
int WfaConRcvBKE(struct station *,unsigned int *,int );
int WfaConRcvVIE(struct station *,unsigned int *,int );
int WfaConRcvVISndBE(struct station *,unsigned int *,int );
int WfaConRcvVISndBK(struct station *,unsigned int *,int );
int WfaConRcvVISnd(struct station *,unsigned int *,int );
int WfaConRcvVISndE(struct station *,unsigned int *,int );
int WfaConRcvVISndVOE(struct station *,unsigned int *,int );
int WfaConRcvConfSndVI(struct station *,unsigned int *,int );
int WfaConRcvVIOnlySndBcastE(struct station *,unsigned int *,int );
int WfaConRcvVOSndBcastE(struct station *,unsigned int *,int );
int WfaConRcvBESnd(struct station *,unsigned int *,int );
int WfaConRcvBESndBcastE(struct station *,unsigned int *,int );
int WfaConRcvVISndBcast (struct station *,unsigned int *,int );
int WfaConRcvBESndBcast (struct station *,unsigned int *,int );
int WfaConRcvVISndBcastE (struct station *,unsigned int *,int );
int WfaConRcvVOSndAllE(struct station *,unsigned int *,int );
int WfaConRcvVISndVIE(struct station *,unsigned int *,int );
int WfaConRcvVOSndVOE(struct station *,unsigned int *,int );
int WfaConRcvVOSndVO(struct station *,unsigned int *,int );
int WfaConRcvBESndE(struct station *,unsigned int *,int );
char traceflag=1; // enable debug packet tracing
consoleProcStatetbl_t consoleProcStatetbl[LAST_TEST+1][10] =
{
/* Ini*/
{WfaConRcvHello,WfaConRcvConf,WfaConRcvVOSnd,WfaConWaitStop,0,0,0,0,0,0},
/* B.D*/
{WfaConRcvHello,WfaConRcvConf,WfaConRcvVOSnd,WfaConRcvVOE,WfaConWaitStop,WfaConWaitStop ,0,0,0,0},
/* B.H*/
{WfaConRcvHello,WfaConRcvConf,WfaConRcvVOSnd2VO,WfaConRcvVOE,WfaConWaitStop ,WfaConWaitStop ,0,0,0,0},
/* B.B*/
{WfaConRcvHello,WfaConRcvConf,WfaConRcvVO ,WfaConRcvVI ,WfaConRcvBE ,WfaConRcvBKE ,WfaConWaitStop,0,0,0},
/* B.M*/
{WfaConRcvHello,WfaConRcvConf,WfaConRcvVIE ,WfaConWaitStop ,0,0,0,0,0,0},
/* M.D */
{WfaConRcvHello,WfaConRcvConf,WfaConRcvVISndBE ,WfaConRcvVISndBK ,WfaConRcvVISnd ,WfaConRcvVISndVOE ,WfaConWaitStop ,0,0,0},
/* B.Z*/
{WfaConRcvHello,WfaConRcvConfSndVI,WfaConRcvVOSndBcastE,WfaConWaitStop ,0,0,0,0},
/* M.Y*/{WfaConRcvHello,WfaConRcvConf,WfaConRcvVISnd,WfaConRcvVO,WfaConRcvBESnd,WfaConRcvBESndBcastE,WfaConWaitStop,0,0,0},
/* L.1*/
{WfaConRcvHello,WfaConRcvConf,WfaConRcvVOSndCyclic, WfaConWaitStop ,0,0,0,0,0,0},
/* A.Y*/
{WfaConRcvHello,WfaConRcvConf,WfaConRcvVISnd ,WfaConRcvVO ,WfaConRcvBESnd ,WfaConRcvBE ,WfaConRcvBESndBcastE,WfaConWaitStop,0,0},
/* B.W*/
{WfaConRcvHello,WfaConRcvConf,WfaConRcvVISndBcast ,WfaConRcvVISndBcast ,WfaConRcvVIE,WfaConWaitStop ,0,0,0,0},
/* A.J*/
{WfaConRcvHello,WfaConRcvConf,WfaConRcvVO ,WfaConRcvVOSndAllE ,WfaConWaitStop ,0,0,0,0,0},
/* M.V*/
{WfaConRcvHello,WfaConRcvConf,WfaConRcvVISnd ,WfaConRcvBESnd ,WfaConRcvVISndE ,WfaConWaitStop ,0,0,0,0},
/* M.U*/
{WfaConRcvHello,WfaConRcvConf,WfaConRcvVISnd ,WfaConRcvBESnd ,WfaConRcvVOSnd ,WfaConRcvVOSndE ,WfaConWaitStop ,0,0,0},
/* A.U*/
{WfaConRcvHello,WfaConRcvConf,WfaConRcvVISnd ,WfaConRcvBE ,WfaConRcvBESnd ,WfaConRcvBE ,WfaConRcvVOSnd ,WfaConRcvVOE,WfaConWaitStop,0},
/* M.L*/
{WfaConRcvHello,WfaConRcvConf,WfaConRcvBESndE ,WfaConWaitStop ,0,0,0,0,0,0},
/* B.K*/
{WfaConRcvHello,WfaConRcvConf,WfaConRcvVISnd ,WfaConRcvBESnd ,WfaConRcvVIE ,WfaConWaitStop ,0,0,0,0},
/* M.B*/
{WfaConRcvHello,WfaConRcvConf,WfaConRcvVO ,WfaConRcvVI ,WfaConRcvBE ,WfaConRcvBKE ,WfaConWaitStop ,0,0,0},
/* M.K*/
{WfaConRcvHello,WfaConRcvConf,WfaConRcvVISnd ,WfaConRcvBESnd ,WfaConRcvVIE ,WfaConWaitStop ,0,0,0,0},
/* M.W*/
{WfaConRcvHello,WfaConRcvConf,WfaConRcvVISndBcast ,WfaConRcvBESndBcast,WfaConRcvVIE,WfaConWaitStop ,0,0,0,0}
};
unsigned int fromlen; // sizeof socket struct
unsigned char dscp, ldscp; // new/last dscp output values
struct sockaddr dst; // sock declarations
struct sockaddr_in target;
struct sockaddr_in from;
struct sockaddr_in local;
int sockflags; // socket call flag
int nsta=0; // Number of stations
struct station stations[NSTA];
char *procname; // dst system name or ip address
int sd,rd; // socket descriptor
void WfaConResetAll();
void IAmDead()
{
printf("Time to Die...\n");
exit(-10);
}
void WfaConResetAll()
{
int r;
reset=1;
printf("\nEntering WfaConResetAll:: ");
alarm(0);
num_retry++;
if(num_retry > MAXRETRY)
IAmDead();
if(reset_recd)
{
reset_recd = 0;
set_dscp(tos_be);
create_apts_msg(APTS_RESET_RESP, txmsg,0);
txmsg[1] = tos_be;
r = sendto(sd, txmsg, 190, sockflags, (struct sockaddr *)&from, sizeof(from));
if (traceflag) mpx("CMD send\n", txmsg, 64);
printf("\nsent RESET RESP\n");
}
else
{
int resp_recd=0;
create_apts_msg(APTS_RESET, txmsg,0);
txmsg[1] = tos_be;
r = sendto(sd, txmsg, 190, sockflags, (struct sockaddr *)&from, sizeof(from));
if (traceflag) mpx("CMD send\n", txmsg, 64);
printf("\nsent RESET \n");
while(!resp_recd)
{
r = recvfrom(sd, rmsg, sizeof(rmsg), 0, (struct sockaddr *)&from, &fromlen);
if (r<0)
{
perror("rcv error:");
exit(1);
}
if(rmsg[10] != APTS_RESET_RESP)
continue;
if (traceflag) mpx("CMD recd\n", rmsg, 64);
alarm(0);
resp_recd=1;
}/* while */
}
}
void resettimer(int period)
{
timeron=period;
}
void* timerthread(void* period)
{
int* per=(int*)period;
exitflag=1;
while(1)
{
sleep(1);
timeron--;
if(!timeron && exitflag)
{
printf("time out\n");
exit(1);
}
}
}
main(int argc, char **argv)
{
int r, flags=0, n, i, id,base=10, bKeepFrom = 0;
struct apts_msg *testcase;
struct station *sta = NULL;
char IP[INET_ADDRSTRLEN],string[128];
char *str,*endptr;
FILE *tmpfile;
consoleProcStatetbl_t func;
for(i=1; i<argc; i++)
{
if(argv[i][0]=='-')
{
if(argv[i][1]=='t')
{
i++;
timeron=atoi(argv[i]);
pthread_create(&time_thr,NULL,timerthread,NULL);
}
else
{
printf("Unrecognized options\n");
exit(1);
}
}
else
{
procname = argv[i]; // gather non-option args here
if( (strncmp(procname,"L.1AP", 4) == 0 ))
{
procname[3] = '\0';
bKeepFrom = 1;
}
else
{
bKeepFrom = 0;
}
}
}
setup_socket();
testcase = (struct apts_msg *) apts_lookup(procname);
sockflags = MSG_DONTWAIT;
tos_vo = 0xD0;
tos_vi = 0xA0;
tos_be = 0x00;
tos_bk = 0x20;
tmpfile = fopen("tos.txt","r+");
if(tmpfile == NULL)
{
printf("Can not find the tos file,proceeding with default values\n");
}
else
{
while(fgets(string,128,tmpfile) != NULL)
{
if(strstr(string,"#"))
continue;
if(strstr(string,"0x"))
{
base = 16;
}
str = strtok(string,",");
tos_vo = strtol(str,&endptr,base);
str = strtok(NULL,",");
tos_vi = strtol(str,&endptr,base);
str = strtok(NULL,",");
tos_be = strtol(str,&endptr,base);
str = strtok(NULL,",");
tos_bk = strtol(str,&endptr,base);
}
}
printf("Using TOS: VO=0x%x,VI=0x%x,BE=0x%x,BK=0x%x\n",
tos_vo,tos_vi,tos_be,tos_bk);
traceflag=1;
while (1)
{
if(nsta)
{
printf("\nWaiting in state %d\n",sta->state);
}
if (( sta== NULL) || (bKeepFrom == 1))
r = recvfrom(sd, rmsg, sizeof(rmsg), flags, (struct sockaddr *)&from, &fromlen);
else
r = recv(sd, rmsg, sizeof(rmsg), flags);
resettimer(INTERSTEP_PERIOD*10);
if (r<0)
{
perror("rcv error:");
exit(1);
}
alarm(0);
tout=0;
/* check some cases */
if (traceflag && strcmp(procname,"L.1"))
{
printf( "APTS Received # length:%d\n", r );
mpx("APTS RX", rmsg, 64);
}
// Do not process unless from remote
if (from.sin_addr.s_addr==0 || from.sin_addr.s_addr==local.sin_addr.s_addr)
{
printf( "Received 0 / local\n" );
continue;
}
if (from.sin_addr.s_addr==target.sin_addr.s_addr)
{
printf( "Received BROADCAST\n" );
continue;
}
if (rmsg[10]==APTS_BCST)
{
printf( "Received BROADCAST, skipping\n" );
continue;
}
/* check some cases */
printf("\r\n cmd is %d",rmsg[11]);
if (rmsg[10]==APTS_HELLO)
{
if((id = get_sta_id(from.sin_addr.s_addr))>=0)
{
if(!reset)
continue;
printf("\n HELLO after reset");
}
else if((id = assign_sta_id(from.sin_addr.s_addr))<0)
{
printf( "Can not assign id,sta list full");
continue;
}
sta = &stations[id];
bzero(sta->ipaddress, 20);
inet_ntop(AF_INET, &(from.sin_addr), IP, INET_ADDRSTRLEN);
printf("ip is %s\n",IP);
strcpy( &(sta->ipaddress[0]), IP);
sta->cmd = testcase->cmd;
sta->cookie = 0;
sta->nsent = 0;
sta->nerr = 0;
sta->msgno = 0;
sta->myid = id;
sta->alreadyCleared = 0;
printf("new_station: size(%d) id=%02d IP address:%s\n", r, id, sta->ipaddress);
if(reset)
reset = 0;
else
nsta++;
printf( "New STA = %d\n", nsta );
sta->state = 0;
sta->statefunc = consoleProcStatetbl[sta->cmd];
}/* if (rmsg[10]==APTS_HELLO) */
else
{
if(reset)
continue;
if((id = get_sta_id(from.sin_addr.s_addr))<0)
{
inet_ntop(AF_INET, &(from.sin_addr), IP, INET_ADDRSTRLEN);
printf("\r\n Unexpected message rcd from ip s_addr=%s sta id=%d", IP, id);
continue;
}
sta = &stations[id];
}/* else */
if(rmsg[10] == APTS_RESET)
{
reset_recd = 1;
printf("\nRcv RESET from STA, sent RESET back to STA, exit\n");
WfaConResetAll();
exit(0);
}
if(rmsg[10] == APTS_RESET_STOP)
{
printf("\r\n Recd Kill from Sta\n");
exit(0);
}
func = (sta->statefunc)[sta->state];
if(!sta->alreadyCleared)
{
func.statefunc(sta,rmsg,r);
}
}/* while loop */
}/* main */