blob: d60566d70cf8fcc8fb507a33c4dd3090c2e33331 [file] [log] [blame]
/****************************************************************************
* (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved
*
*
* LICENSE
*
* License is granted only to Wi-Fi Alliance members and designated
* contractors ($B!H(BAuthorized Licensees$B!I(B)..AN Authorized Licensees are granted
* the non-exclusive, worldwide, limited right to use, copy, import, export
* and distribute this software:
* (i) solely for noncommercial applications and solely for testing Wi-Fi
* equipment; and
* (ii) solely for the purpose of embedding the software into Authorized
* Licensee$B!G(Bs proprietary equipment and software products for distribution to
* its customers under a license with at least the same restrictions as
* contained in this License, including, without limitation, the disclaimer of
* warranty and limitation of liability, below..AN The distribution rights
* granted in clause
* (ii), above, include distribution to third party companies who will
* redistribute the Authorized Licensee$B!G(Bs product to their customers with or
* without such third party$B!G(Bs private label. Other than expressly granted
* herein, this License is not transferable or sublicensable, and it does not
* extend to and may not be used with non-Wi-Fi applications..AN Wi-Fi Alliance
* reserves all rights not expressly granted herein..AN
*.AN
* Except as specifically set forth above, commercial derivative works of
* this software or applications that use the Wi-Fi scripts generated by this
* software are NOT AUTHORIZED without specific prior written permission from
* Wi-Fi Alliance.
*.AN
* Non-Commercial derivative works of this software for internal use are
* authorized and are limited by the same restrictions; provided, however,
* that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of
* such derivative works under a perpetual, payment-free license to use,
* modify, and distribute such derivative works for purposes of testing Wi-Fi
* equipment.
*.AN
* Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse
* or promote products that are derived from or that use this software without
* specific prior written permission from Wi-Fi Alliance.
*
* THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A.AN PARTICULAR PURPOSE,
* ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************
*/
/*
* File: wfa_sock.c
* library functions for TCP and UDP socket creations and handling
* They are common library and shared by DUT, TC and CA.
*
* Revision History:
* 2006/03/10 -- initially created by qhu
* 2006/06/01 -- BETA release by qhu
* 2006/06/13 -- 00.02 release by qhu
* 2006/06/30 -- 00.10 Release by qhu
* 2006/07/10 -- 01.00 Release by qhu
* 2006/09/01 -- 01.05 Release by qhu
* 2007/02/15 -- WMM Extension Beta released by qhu, mkaroshi
* 2007/03/30 -- 01.40 WPA2 and Official WMM Beta Release by qhu
* 2007/04/20 -- 02.00 WPA2 and Official WMM Release by qhu
* 2007/08/15 -- 02.10 WMM-Power Save release by qhu
* 2007/10/10 -- 02.20 Voice SOHO beta -- qhu
* 2007/11/07 -- 02.30 Voice HSO -- qhu
* -- add a compilation flags to wmmfds and wmmps to setFileDesc()
* that match the defintions in wfa_dut.c reported by rmaeder.
*
*/
#ifndef WIN32
#include <pthread.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#include <linux/if.h>
#include <sys/ioctl.h>
#include <sched.h>
#include <fcntl.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <bcmendian.h>
#ifdef TARGETENV_android
#include <asm/mman.h>
#else
#include <sys/mman.h>
#endif
#endif
#include "wfa_debug.h"
#include "wfa_types.h"
#include "wfa_main.h"
#include "wfa_sock.h"
#include "wfa_miscs.h"
int wfaGetifAddr(char *ifname, struct sockaddr_in *sa);
extern unsigned short wfa_defined_debug;
extern BOOL gtgTransac;
extern char gnetIf[];
#ifndef MAXPENDING
#define MAXPENDING 2 /* Maximum outstanding connection requests */
#endif
#ifdef TARGETENV_android
/* These functions are defined inside sys/mman.h for linux
* For android we are defining here as dummy
*/
int mlockall(int flags)
{
return 0;
}
int munlockall(void)
{
return 0;
}
#endif
/*
* wfaCreateTCPServSock(): initially create a TCP socket
* intput: port -- TCP socket port to listen
* return: socket id;
*/
int wfaCreateTCPServSock(unsigned short port)
{
int sock; /* socket to create */
struct sockaddr_in servAddr; /* Local address */
const int on = 1;
/* Create socket for incoming connections */
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
DPRINT_ERR(WFA_ERR, "createTCPServSock socket() failed");
return FALSE;
}
/* Construct local address structure */
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET; /* Internet address family */
servAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
servAddr.sin_port = htons(port); /* Local port */
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on));
/* Bind to the local address */
if (bind(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)
{
DPRINT_ERR(WFA_ERR, "bind() failed");
return FALSE;
}
/* Mark the socket so it will listen for incoming connections */
if (listen(sock, MAXPENDING) < 0)
{
DPRINT_ERR(WFA_ERR, "listen() failed");
return FALSE;
}
return sock;
}
/*
* wfaCreateUDPSock(): create a UDP socket
* input:
ipaddr -- local ip address for test traffic
port -- UDP port to receive and send
* return: socket id
*/
int wfaCreateUDPSock(char *ipaddr, unsigned short port)
{
int udpsock; /* socket to create */
struct sockaddr_in servAddr; /* Local address */
#ifdef WIN32
if((udpsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
#else
if((udpsock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
#endif
{
DPRINT_ERR(WFA_ERR, "createUDPSock socket() failed");
return FALSE;
}
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
DPRINT_INFO(WFA_OUT, "UDP port %i\n", port);
servAddr.sin_port = htons(port);
bind(udpsock, (struct sockaddr *) &servAddr, sizeof(servAddr));
return udpsock;
}
int wfaSetSockMcastSendOpt(int sockfd)
{
#ifdef WIN32
int ttlval = 64;
DPRINT_INFO(WFA_OUT, "MCAST: McastSendOpt: sockfd = %d\r\n",sockfd);
return setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&ttlval, sizeof(int));
#else
unsigned char ttlval = 1;
return setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &ttlval, sizeof(ttlval));
#endif
}
int wfaSetSockMcastRecvOpt(int sockfd, char *mcastgroup)
{
struct ip_mreq mcreq;
int so;
mcreq.imr_multiaddr.s_addr = inet_addr(mcastgroup);
#ifdef WIN32
mcreq.imr_interface.s_addr = INADDR_ANY;
#else
mcreq.imr_interface.s_addr = htonl(INADDR_ANY);
#endif
#ifdef DEBUG
DPRINT_INFO(WFA_OUT, "MCAST: McastRecvOpt: mcastgroup = %s\r\n",mcastgroup);
#endif
so = setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(void *)&mcreq, sizeof(mcreq));
return so;
}
int wfaConnectUDPPeer(int mysock, char *daddr, unsigned short dport)
{
struct sockaddr_in peerAddr;
memset(&peerAddr, 0, sizeof(peerAddr));
peerAddr.sin_family = AF_INET;
#ifndef WIN32
inet_aton(daddr, &peerAddr.sin_addr);
#else
peerAddr.sin_addr.s_addr = inet_addr(daddr);
#endif
peerAddr.sin_port = htons(dport);
connect(mysock, (struct sockaddr *)&peerAddr, sizeof(peerAddr));
return mysock;
}
int wfaConnectTCPPeer(unsigned short sport, char *daddr, unsigned short dport)
{
int tcpsock; /* socket to create */
struct sockaddr_in servAddr; /* Local address */
struct sockaddr_in peerAddr; /* peer address */
#ifdef WIN32
if((tcpsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
#else
if((tcpsock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
#endif
{
DPRINT_ERR(WFA_ERR, "wfaConnectTCPPeer socket() failed");
return FALSE;
}
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
servAddr.sin_port = htons(sport);
if(bind(tcpsock, (struct sockaddr *) &servAddr, sizeof(servAddr)) == -1)
{
DPRINT_ERR(WFA_ERR, "createTCPPeer bind() failed");
return FALSE;
}
memset(&peerAddr, 0, sizeof(peerAddr));
peerAddr.sin_family = AF_INET;
#ifndef WIN32
inet_aton(daddr, &peerAddr.sin_addr);
#else
peerAddr.sin_addr.s_addr = inet_addr(daddr);
#endif
peerAddr.sin_port = htons(dport);
if(connect(tcpsock, (struct sockaddr *)&peerAddr, sizeof(peerAddr)) == -1)
{
DPRINT_ERR(WFA_ERR, "wfaConnectTCPPeer connect() failed");
return FALSE;
}
return tcpsock;
}
/*
* acceptTCPConn(): handle and accept any incoming socket connection request.
* input: serSock -- the socket id to listen
* return: the connected socket id.
*/
int wfaAcceptTCPConn(int servSock)
{
int clntSock; /* Socket descriptor for client */
struct sockaddr_in clntAddr; /* Client address */
unsigned int clntLen; /* Length of client address data structure */
/* Set the size of the in-out parameter */
clntLen = sizeof(clntAddr);
/* Wait for a client to connect */
if ((clntSock = accept(servSock, (struct sockaddr *) &clntAddr,
&clntLen)) < 0)
{
DPRINT_ERR(WFA_ERR, "accept() failed");
exit(1);
}
/* clntSock is connected to a client! */
return clntSock;
}
struct timeval *wfaSetTimer(int secs, int usecs, struct timeval *tv)
{
struct timeval *mytv;
if(gtgTransac != 0)
{
tv->tv_sec = secs ; /* timeout (secs.) */
tv->tv_usec = usecs; /* 0 microseconds */
}
else
{
tv->tv_sec = 0;
tv->tv_usec = 0; /* 0 microseconds */
}
if(tv->tv_sec == 0 && tv->tv_usec == 0)
mytv = NULL;
else
mytv = tv;
return mytv;
}
/* this only set four file descriptors, the main agent fd, control agent
* port fd and traffic generation fd, traffic generator fd.
*/
void wfaSetSockFiDesc(fd_set *fdset, int *maxfdn1, struct sockfds *fds)
{
int i;
FD_ZERO(fdset);
if(fdset != NULL)
FD_SET(*fds->agtfd, fdset);
/* if the traffic generator socket port valid */
if(*fds->tgfd > 0)
{
FD_SET(*fds->tgfd, fdset);
*maxfdn1 = max(*maxfdn1-1, (int)*fds->tgfd) + 1;
}
/* if the traffic generator socket Recv port valid */
if(*fds->tgRevfd > 0)
{
FD_SET(*fds->tgRevfd, fdset);
*maxfdn1 = max(*maxfdn1-1, (int)*fds->tgRevfd) + 1;
}
/* if the control agent socket fd valid */
if(*fds->cafd >0)
{
FD_SET(*fds->cafd, fdset);
*maxfdn1 = max(*maxfdn1-1, (int)*fds->cafd) + 1;
}
/* if any of wmm traffic stream socket fd valid */
for(i = 0; i < WFA_MAX_TRAFFIC_STREAMS; i++)
{
if(fds->wmmfds[i] > 0)
{
if(fds->wmmfds[i] > FD_SETSIZE)
{
// DPRINT_INFO(WFA_OUT, "Size greater than FD_SETSIZE\r\n");
}
FD_SET(fds->wmmfds[i], fdset);
*maxfdn1 = max(*maxfdn1-1, (int)fds->wmmfds[i]) +1;
}
}
#ifdef WFA_WMM_EXT
#ifdef WFA_WMM_PS_EXT
/* if the power save socket port valid */
if(*fds->psfd > 0)
{
FD_SET(*fds->psfd, fdset);
*maxfdn1 = max(*maxfdn1-1, (int)*fds->psfd) + 1;
}
#endif
#endif
return;
}
/*
* wfaCtrlSend(): Send control message/response through
* control link.
* Note: the function used to wfaTcpSend().
*/
int wfaCtrlSend(int sock, unsigned char *buf, int bufLen)
{
int bytesSent = 0;
if(bufLen == 0)
return FALSE;
if(buf == NULL)
DPRINT_INFO(WFA_OUT, "wfaCtrlSend: Buffer null\r\n");
bytesSent = send(sock, buf, bufLen, 0);
if(bytesSent == -1)
{
DPRINT_WARNING(WFA_WNG, "Error sending tcp packet\n");
}
return bytesSent;
}
/*
* wfaCtrlRecv(): Receive control message/response through
* control link.
* Note: the function used to wfaTcpRecv().
*/
int wfaCtrlRecv(int sock, unsigned char *buf)
{
int bytesRecvd = 0;
bytesRecvd = recv(sock, buf, WFA_BUFF_1K-1, 0);
return bytesRecvd;
}
/*
* wfaTrafficSendTo(): Send Traffic through through traffic interface.
* Note: the function used to wfaUdpSendTo().
*/
int wfaTrafficSendTo(int sock, char *buf, int bufLen, struct sockaddr *to)
{
int bytesSent;
bytesSent = sendto(sock, buf, bufLen, MSG_DONTWAIT, to, sizeof(struct sockaddr));
return bytesSent;
}
/*
* wfaTrafficRecv(): Receive Traffic through through traffic interface.
* Note: the function used to wfaRecvSendTo().
*/
int wfaTrafficRecv(int sock, char *buf, struct sockaddr *from)
{
int bytesRecvd =0;
socklen_t addrLen;
#ifdef WIN32
struct sockaddr_in recFrom;
#endif
/* get current flags setting */
#ifndef WIN32
int ioflags = fcntl(sock, F_GETFL, 0);
#ifdef TARGETENV_android
if (gtgTransac)
usleep(50);
#endif
/* set only BLOCKING flag to non-blocking */
fcntl(sock, F_SETFL, ioflags | O_NONBLOCK);
bytesRecvd = recvfrom(sock, buf, MAX_UDP_LEN, 0, from, &addrLen);
#ifdef TARGETENV_android
if (errno == EAGAIN && gtgTransac)
usleep(50);
#endif /* TARGETENV_android */
#else
memset(&recFrom, 0, sizeof(recFrom));
addrLen = sizeof(recFrom);
bytesRecvd = recvfrom(sock, buf, MAX_UDP_LEN, 0, (struct sockaddr *)&recFrom, &addrLen);
#endif
return bytesRecvd;
}
int wfaGetifAddr(char *ifname, struct sockaddr_in *sa)
{
struct ifreq ifr;
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
if(fd < 0)
{
DPRINT_ERR(WFA_ERR, "socket open error\n");
return FALSE;
}
strncpy(ifr.ifr_name, ifname, strlen(ifname));
#ifndef WIN32
ifr.ifr_addr.sa_family = AF_INET;
if(ioctl(fd, SIOCGIFADDR, &ifr) == 0)
{
memcpy(sa, (struct sockaddr_in *)&ifr.ifr_addr, sizeof(struct sockaddr_in));
}
else
{
return FALSE;
}
#else
ifr.ifr_addr.sin_family = AF_INET;
memcpy(sa, (struct sockaddr_in *)&ifr.ifr_addr, sizeof(struct sockaddr_in));
#endif
asd_closeSocket(fd);
return FALSE;
}
/*
* wfaSetProcPriority():
* With the linux 2.6 kernel, it allows an application process dynamically
* adjust its running priority level. In order to achieve higher control of
* packet sending/receiving and timer response, it is helpful to raise the
* process priority level over others and lower it back once it finishes.
*
* This is purely used for performance tuning purpose and not required to
* port if it is not needed.
*/
int wfaSetProcPriority(int set)
{
#ifndef WIN32
int maxprio, currprio;
struct sched_param schp;
memset(&schp, 0, sizeof(schp));
sched_getparam(0, &schp);
currprio = schp.sched_priority;
if(set != 0)
{
if(geteuid() == 0)
{
maxprio = sched_get_priority_max(SCHED_FIFO);
if(maxprio == -1)
{
return FALSE;
}
schp.sched_priority = maxprio;
if(sched_setscheduler(0, SCHED_FIFO, &schp) != 0)
{
}
}
if(mlockall(MCL_CURRENT | MCL_FUTURE) != 0)
{
}
}
else
{
if(geteuid() == 0)
{
schp.sched_priority = 0;
if(sched_setscheduler(0, SCHED_OTHER, &schp) != 0)
{
}
}
munlockall();
}
return currprio;
#else
return 0;
#endif
}