| |
| /**************************************************************************** |
| * (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 |
| |
| } |