blob: f36657fe6bee5a8d4f6012e1e842dc2553e98380 [file] [log] [blame]
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <malloc.h>
/* from mstcpip.h */
#define SIO_RCVALL _WSAIOW(IOC_VENDOR,1)
/* from iphlpapi.h */
#pragma pack(push, 4)
typedef struct mib_ipaddrrow_t {
DWORD dwAddr;
DWORD dwIndex;
DWORD dwMask;
DWORD dwBCastAddr;
DWORD dwReasmSize;
DWORD unused;
} MIB_IPADDRROW;
typedef struct mib_ipaddrtable_t {
DWORD dwNumEntries;
MIB_IPADDRROW table[0];
} MIB_IPADDRTABLE;
#pragma pack(pop)
#define htons contiki_htons /* htons is defined in winsock2 */
#include "uip.h"
#undef htons
#include "tcpip.h"
#include "ctk.h"
#define BUF ((uip_tcpip_hdr *)uip_buf)
typedef DWORD (WINAPI *ARPFUNC)(DWORD, DWORD, DWORD);
extern void debug_printf(char *format, ...);
static void error_exit(const char *message, int value);
static void create_proxyarp(void);
static void delete_proxyarp(void);
static DWORD interfaceindex;
static DWORD proxyaddr;
static SOCKET rawsock = INVALID_SOCKET;
#define END_OF(ARRAY) (ARRAY + sizeof(ARRAY)/sizeof(ARRAY[0]))
#define HOSTADDR() (*(DWORD*)uip_hostaddr)
#define NETMASK() (*(DWORD*)uip_netmask)
#define DELAY_LOAD(NAME,MODULE) \
( GetProcAddress(GetModuleHandle(MODULE), NAME) \
? GetProcAddress(GetModuleHandle(MODULE), NAME) \
: (error_exit("GetProcAddress("#NAME") error: %d\n", GetLastError()), 0))
#define SOCKCTL_(ON,CMD) \
{ unsigned long on = ON; if (SOCKET_ERROR == \
ioctlsocket(rawsock, CMD, &on)) \
error_exit("ioctlsocket("#CMD") error: %d\n", WSAGetLastError()); }
#define SOCKOPT_ON_(OPT,LAYER) \
{ unsigned long on = 1; if (SOCKET_ERROR == \
setsockopt(rawsock, LAYER, OPT, (char*)&on, sizeof(on))) \
error_exit("setsockopt("#OPT") error: %d\n", WSAGetLastError()); }
#define TRAP(ERR,HEAD,TAIL) \
( match(ERR,HEAD,TAIL) ? ERR : (error_exit("send/recv() error: %d\n",ERR),0) )
/*-----------------------------------------------------------------------------------*/
static int match(const int x, const int *head, const int *const tail)
{
for( ;tail != head; ++head) if(*head == x) return 1;
return 0;
}
/*-----------------------------------------------------------------------------------*/
static void
error_exit(const char *message, int value)
{
console_exit();
cprintf(message, value);
exit(EXIT_FAILURE);
}
/*-----------------------------------------------------------------------------------*/
static DWORD
get_interface_index_for_(DWORD ip)
{
DWORD (WINAPI *Table)(MIB_IPADDRTABLE *, DWORD *, BOOL);
DWORD retval;
DWORD size = sizeof(MIB_IPADDRROW);
MIB_IPADDRTABLE *d = 0;
MIB_IPADDRROW *r;
(FARPROC)Table = DELAY_LOAD("GetIpAddrTable","iphlpapi");
do { d = realloc(d, size *= 2); }
while(ERROR_INSUFFICIENT_BUFFER == (retval = Table(d, &size, TRUE)));
if(NO_ERROR != retval) error_exit("GetIpAddrTable error: %d\n", retval);
for(r = d->table; r != d->table + d->dwNumEntries; ++r)
if(r->dwAddr == ip) return retval = r->dwIndex, realloc(d,0), retval;
return error_exit("Parameter error: Unknown host IP address\n", 0), 0;
}
/*-----------------------------------------------------------------------------------*/
static void*
sock_in_addr(unsigned long ipaddr, u16_t port)
{
static struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = port;
addr.sin_addr.s_addr = ipaddr;
return &addr;
}
/*-----------------------------------------------------------------------------------*/
void
rawsock_init(void)
{
DWORD hostaddr;
WSADATA wsadata;
if(WSAStartup(2, &wsadata) != 0) {
error_exit("WSAStartup() error\n", 0);
}
hostaddr = inet_addr(__argv[1]);
if(hostaddr == INADDR_NONE) {
error_exit("Parameter error: Invalid host IP address\n", 0);
}
rawsock = socket(PF_INET, SOCK_RAW, IPPROTO_IP);
if(rawsock == INVALID_SOCKET) {
error_exit("socket() error: %d\n", WSAGetLastError());
}
if(bind(rawsock, sock_in_addr(hostaddr,0), sizeof(struct sockaddr)) == SOCKET_ERROR) {
error_exit("bind() error: %d\n", WSAGetLastError());
}
SOCKOPT_ON_(SO_BROADCAST, SOL_SOCKET);
SOCKOPT_ON_(IP_HDRINCL, IPPROTO_IP);
SOCKCTL_(1, SIO_RCVALL);
SOCKCTL_(1, FIONBIO);
LoadLibrary("iphlpapi"); /* map iphlpapi.dll to process address space */
if(atexit(delete_proxyarp)) error_exit("atexit() error\n", 0);
interfaceindex = get_interface_index_for_(hostaddr);
}
/*-----------------------------------------------------------------------------------*/
void
rawsock_fini(void)
{
delete_proxyarp();
closesocket(rawsock);
rawsock = INVALID_SOCKET;
FreeLibrary(GetModuleHandle("iphlpapi"));
WSACleanup();
}
/*-----------------------------------------------------------------------------------*/
void
rawsock_send(u8_t *hdr, u16_t hdrlen, u8_t *data, u16_t datalen)
{
static const int ignore[] = {WSAEADDRNOTAVAIL,WSAEHOSTUNREACH};
WSABUF sendbuf[2] = {{hdrlen, hdr},{datalen, data}};
DWORD value;
SOCKCTL_(0, FIONBIO); /* switch Non-blocking I/O off */
value = WSASendTo(rawsock, sendbuf, 2, &value, 0
, sock_in_addr(*(unsigned*)BUF->destipaddr,0), sizeof(struct sockaddr_in)
, NULL, NULL);
if(SOCKET_ERROR == value) TRAP(WSAGetLastError(), ignore, END_OF(ignore));
SOCKCTL_(1, FIONBIO); /* switch Non-blocking I/O on */
}
/*-----------------------------------------------------------------------------------*/
u16_t
rawsock_poll(void)
{
static const int ignore[] = {WSAEWOULDBLOCK,WSAEMSGSIZE,WSANOTINITIALISED};
const int nr = (create_proxyarp(),recv(rawsock, uip_buf, UIP_BUFSIZE, 0));
return SOCKET_ERROR != nr ? nr : TRAP(WSAGetLastError(), ignore, END_OF(ignore));
}
/*-----------------------------------------------------------------------------------*/
void
create_proxyarp(void)
{
if(proxyaddr != HOSTADDR()) {
FARPROC f = DELAY_LOAD("CreateProxyArpEntry","iphlpapi");
DWORD retval = (delete_proxyarp(),((ARPFUNC)f)(HOSTADDR(), NETMASK(), interfaceindex));
proxyaddr = HOSTADDR();
debug_printf("CreateProxyArpEntry(%s): %d\n", inet_ntoa(*(struct in_addr*)&proxyaddr), retval);
}
}
/*-----------------------------------------------------------------------------------*/
void
delete_proxyarp(void)
{
if(proxyaddr) {
FARPROC f = DELAY_LOAD("DeleteProxyArpEntry","iphlpapi");
DWORD retval = ((ARPFUNC)f)(HOSTADDR(), NETMASK(), interfaceindex);
debug_printf("DeleteProxyArpEntry(%s): %d\n", inet_ntoa(*(struct in_addr*)&proxyaddr), retval);
proxyaddr = 0;
}
}
/*-----------------------------------------------------------------------------------*/