/* Copyright 2003 Renzo Davoli
* Licensed under the GPL
*/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#ifndef __FreeBSD__
#include <stdint.h>
#endif
#include <libgen.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/uio.h>
#include <sys/poll.h>
#include <libslirp.h>
#include <getopt.h>
#ifdef __FreeBSD__
#include <string.h>
#include <sys/time.h>
#endif
#define SWITCH_MAGIC 0xfeedface
#define BUFSIZE 2048
#define ETH_ALEN 6
int dhcpmgmt=0;
enum request_type { REQ_NEW_CONTROL };
struct request_v3 {
uint32_t magic;
uint32_t version;
enum request_type type;
struct sockaddr_un sock;
};
#ifdef __FreeBSD__
#include "../vde.h"
static char *data_socket = NULL;
static void cleanup()
{
if(data_socket != NULL)
unlink(data_socket);
}
static void sig_handler(int sig)
{
fprintf(stderr, "Caught signal %d, cleaning up and exiting\n", sig);
cleanup(1,NULL);
signal(sig, SIG_DFL);
kill(getpid(), sig);
}
#endif
static int send_fd(char *name, int fddata, struct sockaddr_un *datasock, int group)
{
int pid = getpid();
struct request_v3 req;
int fdctl;
struct sockaddr_un sock;
#ifdef __FreeBSD__
struct timeval tv;
#endif
if((fdctl = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
perror("socket");
exit(1);
}
sock.sun_family = AF_UNIX;
snprintf(sock.sun_path, sizeof(sock.sun_path), "%s", name);
if(connect(fdctl, (struct sockaddr *) &sock, sizeof(sock))){
perror("connect");
exit(1);
}
req.magic=SWITCH_MAGIC;
req.version=3;
req.type=REQ_NEW_CONTROL+((group > 0)?((geteuid()<<8) + group) << 8:0);
req.sock.sun_family=AF_UNIX;
memset(req.sock.sun_path, 0, sizeof(req.sock.sun_path));
#ifdef __FreeBSD__
gettimeofday(&tv, NULL);
snprintf(req.sock.sun_path, sizeof(req.sock.sun_path), "%s.%i.%li",
VDEDATSOCK, pid, tv.tv_usec);
data_socket = strdup(req.sock.sun_path);
#else
sprintf(&req.sock.sun_path[1], "%5d", pid);
#endif
if(bind(fddata, (struct sockaddr *) &req.sock, sizeof(req.sock)) < 0){
perror("bind");
exit(1);
}
if (send(fdctl,&req,sizeof(req),0) < 0) {
perror("send");
exit(1);
}
if (recv(fdctl,datasock,sizeof(struct sockaddr_un),0)<0) {
perror("recv");
exit(1);
}
return fdctl;
}
unsigned char bufin[BUFSIZE];
struct pollfd pollv[]={{STDIN_FILENO,POLLIN|POLLHUP,0},{0,POLLIN|POLLHUP,0}};
char *filename;
char numfd[10];
int slirp_can_output(void)
{
return 1;
}
static int fddata;
static struct sockaddr_un dataout;
#if 0
#define convery2ascii(x) ((x)>=' ' && (x) <= '~')?(x):'.'
void dumppkt(const uint8_t *pkt, int pkt_len)
{
register int i,j;
printf("Packet dump len=%d\n",pkt_len);
if (pkt_len == 0)
return;
for (i=0;i<((pkt_len-1)/16)+1;i++) {
for (j=0;j<16;j++)
if (i*16+j > pkt_len)
printf(" ");
else
printf("%02x ",pkt[i*16+j]);
printf(" ");
for (j=0;j<16;j++)
if (i*16+j > pkt_len)
printf(" ");
else
printf("%c",convery2ascii(pkt[i*16+j]));
printf("\n");
}
}
#endif
void slirp_output(const uint8_t *pkt, int pkt_len)
{
/* slirp -> vde */
//fprintf(stderr,"RX from slirp %d\n",pkt_len);
//dumppkt(pkt,pkt_len);
sendto(fddata,pkt,pkt_len,0,(struct sockaddr *) &dataout, sizeof(struct sockaddr_un));
}
void usage(char *name) {
fprintf(stderr,"Usage: %s [-socket vdesock] [-dhcp] [-network netaddr] \n\t%s [-s vdesock] [-d] [-n netaddr]\n",name,name);
exit(-1);
}
struct option slirpvdeopts[] = {
{"socket",1,NULL,'s'},
{"sock",1,NULL,'s'},
{"vdesock",1,NULL,'s'},
{"unix",1,NULL,'s'},
{"dhcp",0,NULL,'d'},
{"network",0,NULL,'n'},
{NULL,0,0,0}};
int main(int argc, char **argv)
{
char *sockname;
struct sockaddr_un datain;
int datainsize;
int result,nfds;
int group=0;
int connected_fd;
register ssize_t nx;
fd_set rs,ws,xs;
int opt,longindx;
char *netw=NULL;
filename=basename(argv[0]);
sockname="/tmp/vde.ctl";
while ((opt=getopt_long_only(argc,argv,"s:n:d",slirpvdeopts,&longindx)) > 0) {
switch (opt) {
case 's' : sockname=optarg;
break;
case 'd' : dhcpmgmt = 1;
break;
case 'n' : netw=optarg;
break;
default : usage(filename);
break;
}
}
if((fddata = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0){
perror("socket");
exit(1);
}
connected_fd=send_fd(sockname, fddata, &dataout, group);
#ifdef __FreeBSD__
if(signal(SIGINT, sig_handler) < 0) {
perror("signal");
}
signal(SIGPIPE, SIG_IGN); /* FreeBSD 4.x sends SIGPIPE on reset sockets */
#endif
slirp_init(netw);
for(;;) {
FD_ZERO(&rs);
FD_ZERO(&ws);
FD_ZERO(&xs);
nfds= -1;
slirp_select_fill(&nfds,&rs,&ws,&xs);
FD_SET(fddata,&rs);
if (fddata>nfds) nfds=fddata;
result=select(nfds+1,&rs,&ws,&xs,NULL);
//printf("SELECT %d %d\n",nfds,result);
if (FD_ISSET(fddata,&rs)) {
nx=recvfrom(fddata,bufin,BUFSIZE,0,(struct sockaddr *) &datain, &datainsize);
//fprintf(stderr,"TX to slirp %d\n",nx);
result--;
slirp_input(bufin,nx);
//fprintf(stderr,"TX to slirp %d exit\n",nx);
}
if (result > 0) {
//fprintf(stderr,"slirp poll\n");
slirp_select_poll(&rs,&ws,&xs);
//fprintf(stderr,"slirp poll exit\n");
}
}
return(0);
}
syntax highlighted by Code2HTML, v. 0.9.1