summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/modules/netdev/taptun.c
blob: cfe6ef6702b001ede15da8aef1cf570e796368d4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#if defined(SDLMAME_NET_TAPTUN)

#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <errno.h>

#include "emu.h"
#include "osdnet.h"
#include "modules/osdmodule.h"
#include "netdev_module.h"

#ifdef __linux__
#define IFF_TAP     0x0002
#define IFF_NO_PI   0x1000
#define TUNSETIFF     _IOW('T', 202, int)
#endif

class taptun_module : public osd_module, public netdev_module
{
public:

	taptun_module()
	: osd_module(OSD_NETDEV_PROVIDER, "taptun"), netdev_module()
	{
	}
	virtual ~taptun_module() { }

	virtual int init();
	virtual void exit();

	virtual bool probe() { return true; }
};



class netdev_tap : public osd_netdev
{
public:
	netdev_tap(const char *name, class device_network_interface *ifdev, int rate);
	~netdev_tap();

	int send(UINT8 *buf, int len);
	void set_mac(const char *mac);
protected:
	int recv_dev(UINT8 **buf);
private:
	int m_fd;
	char m_ifname[10];
	char m_mac[6];
	UINT8 m_buf[2048];
};

netdev_tap::netdev_tap(const char *name, class device_network_interface *ifdev, int rate)
	: osd_netdev(ifdev, rate)
{
#ifdef __linux__
	struct ifreq ifr;

	m_fd = -1;
	if((m_fd = open("/dev/net/tun", O_RDWR)) == -1) {
		osd_printf_verbose("tap: open failed %d\n", errno);
		return;
	}

	memset(&ifr, 0, sizeof(ifr));
	ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
	sprintf(ifr.ifr_name, "tap-mess-%d-0", getuid());
	if(ioctl(m_fd, TUNSETIFF, (void *)&ifr) == -1) {
		osd_printf_verbose("tap: ioctl failed %d\n", errno);
		close(m_fd);
		m_fd = -1;
		return;
	}
	osd_printf_verbose("netdev_tap: network up!\n");
	strncpy(m_ifname, ifr.ifr_name, 10);
	fcntl(m_fd, F_SETFL, O_NONBLOCK);

#else
	m_fd = -1;
#endif
}

netdev_tap::~netdev_tap()
{
	close(m_fd);
}

void netdev_tap::set_mac(const char *mac)
{
	memcpy(m_mac, mac, 6);
}

int netdev_tap::send(UINT8 *buf, int len)
{
	if(m_fd == -1) return 0;
	len = write(m_fd, buf, len);
	return (len == -1)?0:len;
}

int netdev_tap::recv_dev(UINT8 **buf)
{
	int len;
	if(m_fd == -1) return 0;
	// exit if we didn't receive anything, got an error, got a broadcast or multicast packet,
	// are in promiscuous mode or got a packet with our mac.
	do {
		len = read(m_fd, m_buf, sizeof(m_buf));
	} while((len > 0) && memcmp(get_mac(), m_buf, 6) && !get_promisc() && !(m_buf[0] & 1));
	*buf = m_buf;
	return (len == -1)?0:len;
}

static CREATE_NETDEV(create_tap)
{
	class netdev_tap *dev = global_alloc(netdev_tap(ifname, ifdev, rate));
	return dynamic_cast<osd_netdev *>(dev);
}

int taptun_module::init()
{
	add_netdev("tap", "TAP/TUN Device", create_tap);
	return 0;
}

void taptun_module::exit()
{
	clear_netdev();
}


#else
	#include "modules/osdmodule.h"
	#include "netdev_module.h"

	MODULE_NOT_SUPPORTED(taptun_module, OSD_NETDEV_PROVIDER, "taptun")
#endif


MODULE_DEFINITION(NETDEV_TAPTUN, taptun_module)