1
0
Files
2016-11-30 09:03:17 +08:00

778 lines
16 KiB
C
Executable File

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <linux/in.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/if_arp.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/select.h>
#include <linux/wireless.h>
#ifdef DBG
#include <stdarg.h>
#endif // DBG //
#include "ate.h"
#define VERSION_STR "1.4.0"
#define SIGNAL
#ifdef SIGNAL
#include <signal.h> /* signal */
void init_signals(void);
void signup(int);
#endif // SIGNAL //
#ifndef IFNAMSIZ
#define IFNAMSIZ 16
#endif
#ifndef bzero
#define bzero(d, n) memset((d), (0x00), (n))
#endif
#ifndef os_memcpy
#define os_memcpy(d, s, n) memcpy((d), (s), (n))
#endif
#ifndef os_memset
#define os_memset(s, c, n) memset(s, c, n)
#endif
#ifndef os_strlen
#define os_strlen(s) strlen(s)
#endif
#ifndef os_strncpy
#define os_strncpy(d, s, n) strncpy((d), (s), (n))
#endif
#ifndef os_strchr
#define os_strchr(s, c) strchr((s), (c))
#endif
#ifndef os_strcmp
#define os_strcmp(s1, s2) strcmp((s1), (s2))
#endif
static void RaCfg_Agent(void);
static int OpenRaCfgSocket(void);
static void SanityCheck(u16 command_id, u16 sequence, u16 len);
static void SanityCheckATE(u16 command_id, u16 sequence, u16 len);
static void NetReceive(u8 *inpkt, int len);
static void SendRaCfgAckFrame(int len);
/* GetOpt - only used in main.c */
static int GetOpt(int argc, char *const argv[], const char *optstring);
static void Usage(void);
/* Debugging function - conditional printf and hex dump. Driver wrappers can
* use these for debugging purposes. */
enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR };
/* default : ate_debug_level == 2 */
static int ate_debug_level = MSG_INFO;
#ifdef DBG
static void ate_hexdump(int level, char *str, unsigned char *pSrcBufVA, unsigned long SrcBufLen);
static void ate_printf(int level, char *fmt, ...);
static void ate_hexdump(int level, char *str, unsigned char *pSrcBufVA, unsigned long SrcBufLen)
{
unsigned char *pt;
int x;
if (level < ate_debug_level)
return;
pt = pSrcBufVA;
printf("%s: %p, len = %lu\n",str, pSrcBufVA, SrcBufLen);
for (x=0; x<SrcBufLen; x++)
{
if (x % 16 == 0)
{
printf("0x%04x : ", x);
}
printf("%02x ", ((unsigned char)pt[x]));
if (x%16 == 15) printf("\n");
}
printf("\n");
}
/**
* ate_printf - conditional printf
* @level: priority level (MSG_*) of the message
* @fmt: printf format string, followed by optional arguments
*
* This function is used to print conditional debugging and error messages.
*
* Note: New line '\n' is added to the end of the text when printing to stdout.
*/
static void ate_printf(int level, char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if (level >= ate_debug_level)
{
vprintf(fmt, ap);
printf("\n");
}
va_end(ap);
}
#else // DBG //
#define ate_printf(args...) do { } while (0)
#define ate_hexdump(l,t,b,le) do { } while (0)
#endif // DBG //
static const char *ate_daemon_version =
"ate daemon v" VERSION_STR "\n";
static const char broadcast_addr[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
static unsigned char packet[1536];
static int sock = -1;
static unsigned char buffer[2048];
static char my_eth_addr[6];
static int if_index;
static int do_fork = 1;
static int signup_flag = 1;
static char bridge_ifname[IFNAMSIZ + 1];
static char driver_ifname[IFNAMSIZ + 1];
static int optind = 1;
static int optopt;
static char *optarg;
/* respond to QA by unicast frames if bUnicast == TRUE */
static boolean bUnicast = FALSE;
#ifdef SIGNAL
void signup(int dummy)
{
int s;
struct iwreq pwrq;
unsigned short CmdId;
ate_printf(MSG_DEBUG, "===>%s\n", __FUNCTION__);
/* Send ATESTOP command to driver before I am killed by command line(not by GUI). */
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0)
{
ate_printf(MSG_ERROR, "Socket error in IOCTL\n");
return;
}
bzero(&pwrq, sizeof(pwrq));
CmdId = cpu2be16(RACFG_CMD_ATE_STOP);
os_memcpy(&packet[ETH_HLEN+6], &CmdId, 2);
pwrq.u.data.pointer = (caddr_t) &packet[ETH_HLEN];
pwrq.u.data.length = 12;// 12 == Magic(4) + Cmd Type(2) + Cmd ID(2) + Length(2) + Seq(2)
os_strncpy(pwrq.ifr_name, driver_ifname, IFNAMSIZ);
ioctl(s, RTPRIV_IOCTL_ATE, &pwrq);
close(s);
// It's time to terminate myself.
signup_flag = 0;
}
void init_signals(void)
{
struct sigaction sa;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask, SIGHUP);
sigaddset(&sa.sa_mask, SIGTERM);
sigaddset(&sa.sa_mask, SIGABRT);
sa.sa_handler = signup;
sigaction(SIGHUP, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGABRT, &sa, NULL);
}
#endif // SIGNAL //
int main(int argc, char *argv[])
{
pid_t pid;
int c = 0;
#ifdef SIGNAL
init_signals();
#endif
/* initialize interface */
os_memset(bridge_ifname, 0, IFNAMSIZ + 1);
os_memset(driver_ifname, 0, IFNAMSIZ + 1);
/* set default interface name */
os_memcpy(bridge_ifname, "br0", 4);
os_memcpy(driver_ifname, "ra0", 4);
/* get interface name from arguments */
for (;;)
{
c = GetOpt(argc, argv, "b:hui:vdq");
if (c < 0)
break;
switch (c)
{
case 'b':
{
os_memset(bridge_ifname, 0, IFNAMSIZ + 1);
os_memcpy(bridge_ifname, optarg, os_strlen(optarg));
break;
}
case 'h':
Usage();
return -1;
case 'u':
bUnicast = TRUE;
break;
case 'i':
{
os_memset(driver_ifname, 0, IFNAMSIZ + 1);
os_memcpy(driver_ifname, optarg, os_strlen(optarg));
break;
}
case 'v':
printf("%s\n", ate_daemon_version);
break;
case 'd':
#ifndef DBG
printf("Debugging disabled without "
"-DDBG compile time "
"option.\n");
return -1;
#else // !DBG //
ate_debug_level--;
break;
#endif // !DBG //
case 'q':
#ifndef DBG
printf("Debugging disabled without "
"-DDBG compile time "
"option.\n");
return -1;
#else // !DBG //
ate_debug_level++;
break;
#endif // !DBG //
default:
/* error */
Usage();
return -1;
}
}
/* background ourself */
if (do_fork)
{
pid = fork();
}
else
{
pid = getpid();
}
switch (pid)
{
case -1:
/* error */
perror("fork/getpid");
return -1;
case 0:
/* child, success */
break;
default:
/* parent, success */
if (do_fork)
return 0;
break;
}
RaCfg_Agent();
return 0;
}
static void RaCfg_Agent()
{
int n, count;
struct timeval tv;
fd_set readfds;
unsigned short rcv_protocol;
// struct iwreq pwrq;
// unsigned short CmdId;
if (OpenRaCfgSocket() != 0)
{
return;
}
/* QA will send ATESTART to driver via me when it starts */
#if 0
/* Stop AP first */
/* pass command to driver */
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0)
{
ate_printf(MSG_ERROR, "Socket error in IOCTL\n");
return;
}
bzero(&pwrq, sizeof(pwrq));
CmdId = cpu2le16(RACFG_CMD_ATE_START);
os_memcpy(&packet[20], &CmdId, 2);
pwrq.u.data.pointer = (caddr_t) &packet[14];
pwrq.u.data.length = 8;
//os_strncpy(pwrq.ifr_name, "ra0", IFNAMSIZ);
os_memcpy(pwrq.ifr_name, driver_ifname, IFNAMSIZ);
ioctl(s, RTPRIV_IOCTL_ATE, &pwrq);
close(s);
#endif
/*
* Loop to recv cmd from host
* to start up RT28xx
*/
ate_printf(MSG_DEBUG, "Ralink ATE agent program start\n");
tv.tv_sec=1;
tv.tv_usec=0;
while (signup_flag)
{
FD_ZERO(&readfds);
FD_SET(sock,&readfds);
//count = select(sock+1,&readfds,NULL,NULL,&tv);
count = select(sock+1,&readfds,NULL,NULL,NULL);
if (count < 0)
{
ate_printf(MSG_ERROR, "socket select error\n");
perror("select failed():");
continue;
}
else if (count == 0)
{
continue;
//usleep(1000);
}
else
{
/* Data is available now. */
if (FD_ISSET(sock, &readfds))
{
if ((n = recvfrom(sock, buffer, 2048, 0, NULL, NULL)) > 0)
{
os_memcpy(&rcv_protocol, buffer+12, 2);
/* recv the protocol we are waiting */
if (rcv_protocol == be2cpu16/*ntohs*/(ETH_P_RACFG))
{
ate_printf(MSG_DEBUG, "NetReceive\n");
NetReceive(buffer, n);
}
}
}
}
}
/* QA will send ATESTOP to driver via me when it is closed. */
#if 0
/* Start AP */
/* pass command to driver */
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0)
{
ate_printf(MSG_ERROR, "Socket error in IOCTL\n");
return;
}
bzero(&pwrq, sizeof(pwrq));
CmdId = cpu2le16(RACFG_CMD_ATE_STOP);
os_memcpy(&packet[20], &CmdId, 2);
pwrq.u.data.pointer = (caddr_t) &packet[14];
pwrq.u.data.length = 8;
os_strncpy(pwrq.ifr_name, driver_ifname, IFNAMSIZ);
ioctl(s, RTPRIV_IOCTL_ATE, &pwrq);
close(s);
#endif
ate_printf(MSG_DEBUG, "Ralink ATE agent is closed.\n");
close(sock);
}
static int OpenRaCfgSocket()
{
// struct ifreq ethreq;
struct ifreq ifr;
struct sockaddr_ll addr;
// struct in_addr own_ip_addr;
if ((sock=socket(PF_PACKET, SOCK_RAW, cpu2be16/*htons*/(ETH_P_RACFG))) < 0)
{
perror("socket");
return -1;
}
os_memset(&ifr, 0, sizeof(ifr));
#ifdef CONFIG_LAN_WAN_SUPPORT
os_memcpy(ifr.ifr_name, "eth2.1" , 7);
#else
os_memcpy(ifr.ifr_name, bridge_ifname , IFNAMSIZ);
#endif
if (ioctl(sock, SIOCGIFINDEX, &ifr) != 0)
{
perror("ioctl(SIOCGIFINDEX)(eth_sock)");
goto close;
}
os_memset(&addr, 0, sizeof(addr));
addr.sll_family = AF_PACKET;
addr.sll_ifindex = ifr.ifr_ifindex;
if_index = ifr.ifr_ifindex;
if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0)
{
perror("bind");
goto close;
}
if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0)
{
perror("ioctl(SIOCGIFHWADDR)(eth_sock)");
goto close;
}
os_memcpy(my_eth_addr, ifr.ifr_hwaddr.sa_data, 6);
return 0;
close:
close(sock);
sock = -1;
return (-1);
}
/*
* The Data field of RaCfgAck Frame always is empty
* during bootstrapping state
*/
static void SendRaCfgAckFrame(int len)
{
struct ethhdr *p_ehead;
struct sockaddr_ll socket_address;
unsigned char *header, *data;
int send_result = 0;
header = &packet[0];
data = &packet[14];
p_ehead = (struct ethhdr *)&packet[0];
socket_address.sll_family = PF_PACKET;
socket_address.sll_protocol = cpu2be16/*htons*/(ETH_P_RACFG);
socket_address.sll_ifindex = if_index;
socket_address.sll_pkttype = (bUnicast == FALSE) ? PACKET_BROADCAST : PACKET_OTHERHOST;
socket_address.sll_hatype = ARPHRD_ETHER;
socket_address.sll_halen = ETH_ALEN;
bzero(&socket_address.sll_addr[0], 8);
if (bUnicast == FALSE)
{
/* respond to QA by broadcast frame */
os_memcpy(&socket_address.sll_addr[0], broadcast_addr, 6);
}
else
{
/* respond to QA by unicast frame */
os_memcpy(&socket_address.sll_addr[0], p_ehead->h_dest, 6);
}
send_result = sendto(sock, &packet[0], len, 0, (struct sockaddr *)&socket_address, sizeof(socket_address));
ate_printf(MSG_DEBUG, "response send bytes = %d\n", send_result);
}
static void SanityCheck( u16 Command_Id, u16 Sequence, u16 Len)
{
/* Check for length and ID */
if (((Command_Id == RACFG_CMD_ATE_START) || (Command_Id == RACFG_CMD_ATE_STOP)) && (Len == 0))
{
if (Command_Id == RACFG_CMD_ATE_START)
{
ate_printf(MSG_DEBUG, "Cmd:ATE Start\n");
}
else
{
ate_printf(MSG_DEBUG, "Cmd:ATE Stop\n");
}
}
else
{
/* message for debug */
ate_printf(MSG_DEBUG, "command id from QA = %x\n", Command_Id);
}
return;
}
static void SanityCheckATE(u16 Command_Id, u16 Sequence, u16 Len)
{
/* message for debug */
ate_printf(MSG_DEBUG, "command id from ATE GUI = %x\n", Command_Id);
return;
}
static void NetReceive(u8 *inpkt, int len)
{
struct ethhdr *p_ehead;
struct racfghdr *p_racfgh;
u16 Command_Type;
u16 Command_Id;
u16 Sequence;
u16 Len;
struct iwreq pwrq;
int s;
pid_t pid;
/*
* Check packet len
*/
if (len < (ETH_HLEN + 12/* sizeof(struct racfghdr) */))
{
ate_printf(MSG_ERROR, "packet len is too short!\n");
return;
}
p_ehead = (struct ethhdr *) inpkt;
p_racfgh = (struct racfghdr *) &inpkt[ETH_HLEN];
/*
* 1. Check if dest mac is my mac or broadcast mac
* 2. Ethernet Protocol ID == ETH_P_RACFG
* 3. RaCfg Frame Magic Number
*/
if ((p_ehead->h_proto == cpu2be16/*htons*/(ETH_P_RACFG)) &&
((strncmp(my_eth_addr, (char *)p_ehead->h_dest, 6) == 0) || (strncmp(broadcast_addr, (char *)p_ehead->h_dest, 6) == 0))&&
(be2cpu32/*ntohl*/(p_racfgh->magic_no) == RACFG_MAGIC_NO))
{
Command_Type = be2cpu16(p_racfgh->comand_type);
if ((Command_Type & RACFG_CMD_TYPE_PASSIVE_MASK) != RACFG_CMD_TYPE_ETHREQ)
{
ate_printf(MSG_ERROR, "Command_Type error = %x\n", Command_Type);
return;
}
}
else
{
ate_printf(MSG_ERROR, "protocol or magic error\n");
return;
}
Command_Id = be2cpu16(p_racfgh->comand_id);
Sequence = be2cpu16(p_racfgh->sequence);
Len = be2cpu16(p_racfgh->length);
ate_hexdump(MSG_MSGDUMP, "NetReceive : frame\n", p_ehead->h_dest, (PRE_PAYLOADLEN + Len));
if (((Command_Id & (1 << 8)) == 0))
{
SanityCheck(Command_Id, Sequence, Len);
}
else
{
SanityCheckATE(Command_Id, Sequence, Len);
}
/* pass command to driver */
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0)
{
ate_printf(MSG_ERROR, "Socket error in IOCTL\n");
return;
}
bzero(&pwrq, sizeof(pwrq));
bzero(&packet[0], 1536);
//
// Tell my pid to ra0 with RACFG_CMD_ATE_STOP command.
// It has 4-bytes content containing my pid.
//
if (Command_Id == RACFG_CMD_ATE_STOP)
{
pid = getpid();
// stuff my pid into the content
os_memcpy(&p_racfgh->data[0], (u8 *)&pid, sizeof(pid));
// We have content now.
Len += sizeof(pid);
p_racfgh->length = cpu2be16(Len);
os_memcpy(&packet[14], p_racfgh, Len + 12);
}
else
{
os_memcpy(&packet[14], p_racfgh, Len + 12);
}
pwrq.u.data.pointer = (caddr_t) &packet[14];
pwrq.u.data.length = Len + 12;
os_strncpy(pwrq.ifr_name, driver_ifname, IFNAMSIZ);
ioctl(s, RTPRIV_IOCTL_ATE, &pwrq);
close(s);
/* add ack bit to command type */
p_racfgh = (struct racfghdr *)&packet[14];
p_racfgh->comand_type = p_racfgh->comand_type | cpu2be16/*htons*/(~RACFG_CMD_TYPE_PASSIVE_MASK);
/* prepare ethernet header */
if (bUnicast == FALSE)
{
/* respond to QA by broadcast frame */
os_memcpy(&packet[0], broadcast_addr, 6);
}
else
{
/* respond to QA by unicast frame */
os_memcpy(&packet[0], p_ehead->h_source, 6);
}
p_ehead = (struct ethhdr *)&packet[0];
os_memcpy(p_ehead->h_source, my_eth_addr, 6);
p_ehead->h_proto = cpu2be16/*htons*/(ETH_P_RACFG);
// determine the length to send and send Ack
{
u32 length;
length = be2cpu16/*ntohs*/(p_racfgh->length) + 14 + 12;
if (length < 60)
{
length = 60;
}
else if (length > 1514)
{
ate_printf(MSG_ERROR, "response ethernet length is too long\n");
return;
}
SendRaCfgAckFrame(length);
}
}
static int GetOpt(int argc, char *const argv[], const char *optstring)
{
static int optchr = 1;
char *cp;
if (optchr == 1)
{
if (optind >= argc)
{
/* all arguments processed */
return EOF;
}
if (argv[optind][0] != '-' || argv[optind][1] == '\0')
{
/* no option characters */
return EOF;
}
}
if (os_strcmp(argv[optind], "--") == 0)
{
/* no more options */
optind++;
return EOF;
}
optopt = argv[optind][optchr];
cp = os_strchr(optstring, optopt);
if (cp == NULL || optopt == ':')
{
if (argv[optind][++optchr] == '\0')
{
optchr = 1;
optind++;
}
return '?';
}
if (cp[1] == ':')
{
/* Argument required */
optchr = 1;
if (argv[optind][optchr + 1])
{
/* No space between option and argument */
optarg = &argv[optind++][optchr + 1];
}
else if (++optind >= argc)
{
/* option requires an argument */
return '?';
}
else
{
/* Argument in the next argv */
optarg = argv[optind++];
}
}
else
{
/* No argument */
if (argv[optind][++optchr] == '\0')
{
optchr = 1;
optind++;
}
optarg = NULL;
}
return *cp;
}
static void Usage(void)
{
printf("%s\n\n\n"
"usage:\n"
" ated [-huvd]"
"[-b<br_ifname>] \\\n"
"[-i<driver_ifname>] \\\n"
"\n",
ate_daemon_version);
printf("options:\n"
" -b = bridge interface name\n"
" -h = show this help text\n"
" -u = respond to QA by unicast frame\n"
" -i = driver interface name\n"
" -v = show version\n"
" -d = increase debugging verbosity (-dd even more)\n"
" -q = decrease debugging verbosity (-qq even less)\n");
printf("example 1:\n"
" ated -h\n");
printf("example 2:\n"
" ated -bbr1 -ira1 -v\n");
printf("example 3:\n"
" ated -u\n");
printf("example 4:\n"
" ated -d\n");
}