| /* |
| * Copyright (c) 2011-2012 Qualcomm Atheros Inc. |
| * |
| * 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 <sys/types.h> |
| #include <sys/file.h> |
| #include <sys/ioctl.h> |
| #include <sys/errno.h> |
| #include <sys/socket.h> |
| #include <linux/types.h> |
| #include <netinet/in.h> |
| #include <netinet/tcp.h> |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <getopt.h> |
| #include <sys/time.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <signal.h> |
| |
| #include <time.h> |
| #include "artagent.h" |
| #include "libtcmd.h" |
| |
| static int sid, cid, aid; |
| static char ar6kifname[32]; |
| unsigned int readLength = 0; |
| unsigned char line[LINE_ARRAY_SIZE]; |
| int cmdId,cmdLen; |
| |
| void callback_rx(void *buf, int len) |
| { |
| int length, version; |
| |
| /* skip cmd id, act */ |
| buf += 2 * sizeof(unsigned int); |
| unsigned char *reply = (unsigned char*)buf; |
| length = *(unsigned short *)&(reply[0]); |
| version = (unsigned char)(reply[2]); |
| |
| readLength = *(unsigned int *)&(reply[4]); |
| //printf("Version %d rx length %d read Length %d\n",version,length,readLength); |
| memcpy((void*)line, (void*)&(reply[8]),readLength); |
| } |
| |
| static int initInterface(char *ifname) |
| { |
| int err = 0; |
| err = tcmd_tx_init(ifname, callback_rx); |
| return err; |
| } |
| |
| static int wmiSend(unsigned char *cmdBuf, unsigned int len, unsigned int totalLen, unsigned char version, bool resp) |
| { |
| TC_CMDS tCmd; |
| int err=0; |
| |
| memset(&tCmd,0,sizeof(tCmd)); |
| |
| tCmd.hdr.testCmdId = TC_CMDS_ID; |
| tCmd.hdr.u.parm.length = totalLen; |
| tCmd.hdr.u.parm.version = version; |
| tCmd.hdr.u.parm.bufLen = len; // less than 256 |
| memcpy((void*)tCmd.buf, (void*)cmdBuf, len); |
| |
| if ((err = tcmd_tx((char*)&tCmd, sizeof(tCmd), resp))) { |
| fprintf(stderr, "tcmd_tx had error: %s!\n", strerror(err)); |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
| static void cleanup(int sig) |
| { |
| if (cid>=0) { |
| close(cid); |
| } |
| if (sid>=0) { |
| close(sid); |
| } |
| } |
| |
| int sock_init(int port) |
| { |
| int sockid; |
| struct sockaddr_in myaddr; |
| socklen_t sinsize; |
| int i, res; |
| |
| /* Create socket */ |
| sockid = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); |
| if (sockid == -1) { |
| perror(__FUNCTION__); |
| printf("Create socket to PC failed\n"); |
| return -1; |
| } |
| |
| i = 1; |
| res = setsockopt(sockid, SOL_SOCKET, SO_REUSEADDR, (char *)&i, sizeof(i)); |
| if (res == -1) { |
| close(sockid); |
| return -1; |
| } |
| |
| i = 1; |
| res = setsockopt(sockid, IPPROTO_TCP, TCP_NODELAY, (char *)&i, sizeof(i)); |
| if (res == -1) { |
| close(sockid); |
| return -1; |
| } |
| |
| myaddr.sin_family = AF_INET; |
| myaddr.sin_port = htons(port); |
| myaddr.sin_addr.s_addr = htonl(INADDR_ANY); |
| |
| memset(&(myaddr.sin_zero), 0, 8); |
| |
| res = bind(sockid, (struct sockaddr *)&myaddr, sizeof(struct sockaddr)); |
| |
| if (res != 0) { |
| perror(__FUNCTION__); |
| printf("Bind failed\n"); |
| close(sockid); |
| return -1; |
| } |
| |
| if (listen(sockid, 4) == -1) { |
| perror(__FUNCTION__); |
| printf("Listen failed\n"); |
| close(sockid); |
| return -1; |
| } |
| |
| printf("Waiting for client to connect...\n"); |
| |
| sinsize = sizeof(struct sockaddr_in); |
| if ((cid = accept(sockid, (struct sockaddr *)&myaddr, &sinsize)) == -1) { |
| printf("Accept failed\n"); |
| close(sockid); |
| return -1; |
| } |
| |
| i = 1; |
| res = setsockopt(cid, IPPROTO_TCP, TCP_NODELAY, (char *)&i, sizeof(i)); |
| if (res == -1) { |
| printf("cannot set NOdelay for cid\n"); |
| close(sockid); |
| return -1; |
| } |
| printf("Client connected!\n"); |
| |
| return sockid; |
| } |
| |
| int sock_recv(int sockid, unsigned char *buf, int buflen) |
| { |
| int recvbytes; |
| recvbytes = recv(sockid, buf, buflen, 0); |
| if (recvbytes == 0) { |
| printf("Connection close!? zero bytes received\n"); |
| return -1; |
| } else if (recvbytes > 0) { |
| return recvbytes; |
| } |
| return -1; |
| } |
| |
| int sock_send(int sockid, unsigned char *buf, int bytes) |
| { |
| int cnt; |
| unsigned char* bufpos = buf; |
| while (bytes) { |
| cnt = write(sockid, bufpos, bytes); |
| |
| if (!cnt) { |
| break; |
| } |
| if (cnt == -1) { |
| if (errno == EINTR) { |
| continue; |
| } else { |
| return -1; |
| } |
| } |
| |
| bytes -= cnt; |
| bufpos += cnt; |
| } |
| return (bufpos - buf); |
| } |
| |
| static void print_help(char *pname) |
| { |
| printf("An agent program to connect ART host and AR6K device, must be\n"); |
| printf("started after AR6K device driver is installed.\n\n"); |
| printf("Usage: %s ifname fragsize\n\n", pname); |
| printf(" ifname AR6K interface name\n"); |
| printf(" fragsize Fragment size, must be multiple of 4\n\n"); |
| printf("Example:\n"); |
| printf("%s eth1 80\n\n", pname); |
| } |
| |
| int main (int argc, char **argv) |
| { |
| int recvbytes=0,bytesRcvd=0; |
| int chunkLen = 0; |
| unsigned char *bufpos; |
| int reducedARTPacket = 1; |
| int frag_size = 200; |
| //int i=0; |
| int port = ART_PORT; |
| bool resp = false; |
| bool firstpacket = true; |
| |
| struct sigaction sa; |
| |
| printf("setup signal\n"); |
| memset(&sa, 0, sizeof(struct sigaction)); |
| |
| sa.sa_flags = SA_NOCLDSTOP; |
| sa.sa_handler = cleanup; |
| |
| printf("before call sigaction\n"); |
| sigaction(SIGTERM, &sa, NULL); |
| sigaction(SIGINT, &sa, NULL); |
| sigaction(SIGHUP, &sa, NULL); |
| sigaction(SIGABRT, &sa, NULL); |
| |
| cid = sid = aid = -1; |
| printf("setup ifname\n"); |
| memset(ar6kifname, '\0', sizeof(ar6kifname)); |
| |
| if (argc == 1 ) { |
| print_help(argv[0]); |
| return -1; |
| } |
| |
| if (argc > 1 ) { |
| strcpy(ar6kifname, argv[1]); |
| } |
| else { |
| strcpy(ar6kifname, "wlan0"); |
| } |
| |
| if (argc > 2) { |
| frag_size = atoi(argv[2]); |
| } |
| |
| if (argc > 3) { |
| port = atoi(argv[3]); |
| } |
| |
| if (port == 0) |
| port = ART_PORT; |
| else if (port < 0 || port >65534) { |
| printf("Invalid port number\n"); |
| goto main_exit; |
| } |
| |
| //NOTE: issue with bigger size on ath6kl driver.. |
| if ( ((frag_size == 0) || ((frag_size % 4) != 0)) || (frag_size > 200) ) { |
| printf("Invalid fragsize, should be multiple of 4 and frag size less than 200\n"); |
| goto main_exit; |
| } |
| |
| if ( initInterface(ar6kifname) ) { |
| printf("Init interface cfg80211 failed\n"); |
| cleanup(0); |
| return -1; |
| } |
| |
| printf("open sock\n"); |
| sid = sock_init(port); |
| if (sid < 0) { |
| printf("Create socket to ART failed\n"); |
| cleanup(0); |
| return -1; |
| } |
| |
| if ((recvbytes=sock_recv(cid, line, LINE_ARRAY_SIZE)) < 0) { |
| printf("Cannot nego packet size\n"); |
| cleanup(0); |
| return -1; |
| } |
| |
| printf("Get nego bytes %d\n", recvbytes); |
| |
| if (1 == (*(unsigned int *)line)) { |
| reducedARTPacket = 1; |
| printf("Not supporting reducedARTPacket\n"); |
| goto main_exit; |
| } |
| else { |
| reducedARTPacket = 0; |
| } |
| |
| sock_send(cid, &(line[0]), 1); |
| |
| printf("Ready to loop for art packet reduce %d\n", reducedARTPacket); |
| |
| while (1) { |
| //printf("wait for tcp socket\n"); |
| if ((recvbytes = sock_recv(cid, line, LINE_ARRAY_SIZE)) < 0) { |
| printf("Cannot recv packet size %d\n", recvbytes); |
| cleanup(0); |
| return -1; |
| } |
| |
| bytesRcvd = recvbytes; |
| readLength = 0; |
| resp = false; |
| |
| if ( firstpacket == true ) |
| { |
| cmdLen = *(unsigned short *)&(line[0]); |
| cmdId = *(unsigned char *)&(line[2]); |
| |
| printf("->FW len %d Command %d recvbytes %d\n",cmdLen,cmdId,recvbytes); |
| firstpacket = false; |
| } |
| |
| if (!reducedARTPacket) { |
| //printf("Recived bytes from NART %d frag size %d\n",recvbytes,frag_size); |
| bufpos = line; |
| |
| while (recvbytes) { |
| if (recvbytes > frag_size) { |
| chunkLen = frag_size; |
| } else { |
| chunkLen = recvbytes; |
| } |
| |
| //we have to find out whether we need a resp or not for the last packet.. |
| recvbytes-=chunkLen; |
| |
| if ( recvbytes <=0 ) |
| { |
| resp = true; |
| firstpacket = true; //look for first packet again.. |
| } |
| |
| //printf("Chunk Len %d total size %d respNeeded %d\n",chunkLen,bytesRcvd,resp); |
| wmiSend(bufpos, chunkLen, bytesRcvd, 1, resp); |
| |
| bufpos+=chunkLen; |
| } |
| } |
| |
| //line and readLength is populated in the callback |
| if ((REG_WRITE_CMD_ID != line[0]) && (MEM_WRITE_CMD_ID != line[0]) && |
| (M_PCI_WRITE_CMD_ID != line[0]) && (M_PLL_PROGRAM_CMD_ID != line[0]) && |
| (M_CREATE_DESC_CMD_ID != line[0])) { |
| printf("<- N/ART len %d Command %d status %d\n", readLength,(int)line[0],(int)line[4]); |
| sock_send(cid, line, readLength); |
| } else { |
| printf("<- N/ART ACK Command %d\n", (int)line[0]); |
| sock_send(cid, &(line[0]), 1); |
| } |
| } |
| |
| |
| main_exit: |
| printf("Normal exit\n"); |
| cleanup(0); |
| return 0; |
| } |