forked from tonioni/WinUAE
-
Notifications
You must be signed in to change notification settings - Fork 1
/
ethernet.cpp
293 lines (274 loc) · 6 KB
/
ethernet.cpp
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
#include "sysconfig.h"
#include "sysdeps.h"
#include "ethernet.h"
#ifdef _WIN32
#include "win32_uaenet.h"
#endif
#include "threaddep/thread.h"
#include "options.h"
#include "traps.h"
#include "sana2.h"
#include "uae/slirp.h"
#include "gui.h"
#include "rommgr.h"
#ifndef HAVE_INET_ATON
static int inet_aton(const char *cp, struct in_addr *ia)
{
uint32_t addr = inet_addr(cp);
if (addr == 0xffffffff)
return 0;
ia->s_addr = addr;
return 1;
}
#endif
struct ethernet_data
{
ethernet_gotfunc *gotfunc;
ethernet_getfunc *getfunc;
void *userdata;
};
#define SLIRP_PORT_OFFSET 0
static const int slirp_ports[] = { 21, 22, 23, 80, 0 };
static struct ethernet_data *slirp_data;
static bool slirp_inited;
uae_sem_t slirp_sem1, slirp_sem2;
static int netmode;
static struct netdriverdata slirpd =
{
UAENET_SLIRP,
_T("slirp"), _T("SLIRP User Mode NAT"),
1500,
{ 0x00, 0x00, 0x00, 50, 51, 52 },
{ 0x00, 0x00, 0x00, 50, 51, 52 },
1
};
static struct netdriverdata slirpd2 =
{
UAENET_SLIRP_INBOUND,
_T("slirp_inbound"), _T("SLIRP + Open ports (21-23,80)"),
1500,
{ 0x00, 0x00, 0x00, 50, 51, 52 },
{ 0x00, 0x00, 0x00, 50, 51, 52 },
1
};
void slirp_output (const uint8_t *pkt, int pkt_len)
{
if (!slirp_data)
return;
gui_flicker_led(LED_NET, 0, gui_data.net | 1);
uae_sem_wait (&slirp_sem1);
slirp_data->gotfunc (slirp_data->userdata, pkt, pkt_len);
uae_sem_post (&slirp_sem1);
}
void ethernet_trigger (struct netdriverdata *ndd, void *vsd)
{
if (!ndd)
return;
gui_flicker_led(LED_NET, 0, gui_data.net | 2);
switch (ndd->type)
{
case UAENET_SLIRP:
case UAENET_SLIRP_INBOUND:
{
struct ethernet_data *ed = (struct ethernet_data*)vsd;
if (slirp_data) {
uae_u8 pkt[4000];
int len = sizeof pkt;
int v;
uae_sem_wait (&slirp_sem1);
v = slirp_data->getfunc(ed->userdata, pkt, &len);
uae_sem_post (&slirp_sem1);
if (v) {
uae_sem_wait (&slirp_sem2);
uae_slirp_input(pkt, len);
uae_sem_post (&slirp_sem2);
}
}
}
return;
#ifdef WITH_UAENET_PCAP
case UAENET_PCAP:
uaenet_trigger (vsd);
return;
#endif
}
}
int ethernet_open (struct netdriverdata *ndd, void *vsd, void *user, ethernet_gotfunc *gotfunc, ethernet_getfunc *getfunc, int promiscuous, const uae_u8 *mac)
{
switch (ndd->type)
{
case UAENET_SLIRP:
case UAENET_SLIRP_INBOUND:
{
struct ethernet_data *ed = (struct ethernet_data*)vsd;
ed->gotfunc = gotfunc;
ed->getfunc = getfunc;
ed->userdata = user;
slirp_data = ed;
uae_sem_init (&slirp_sem1, 0, 1);
uae_sem_init (&slirp_sem2, 0, 1);
uae_slirp_init();
for (int i = 0; i < MAX_SLIRP_REDIRS; i++) {
struct slirp_redir *sr = &currprefs.slirp_redirs[i];
if (sr->proto) {
struct in_addr a;
if (sr->srcport == 0) {
inet_aton("10.0.2.15", &a);
uae_slirp_redir (0, sr->dstport, a, sr->dstport);
} else {
#ifdef HAVE_STRUCT_IN_ADDR_S_UN
a.S_un.S_addr = sr->addr;
#else
a.s_addr = sr->addr;
#endif
uae_slirp_redir (sr->proto == 1 ? 0 : 1, sr->dstport, a, sr->srcport);
}
}
}
if (ndd->type == UAENET_SLIRP_INBOUND) {
struct in_addr a;
inet_aton("10.0.2.15", &a);
for (int i = 0; slirp_ports[i]; i++) {
int port = slirp_ports[i];
int j;
for (j = 0; j < MAX_SLIRP_REDIRS; j++) {
struct slirp_redir *sr = &currprefs.slirp_redirs[j];
if (sr->proto && sr->dstport == port)
break;
}
if (j == MAX_SLIRP_REDIRS)
uae_slirp_redir (0, port + SLIRP_PORT_OFFSET, a, port);
}
}
netmode = ndd->type;
uae_slirp_start ();
}
return 1;
#ifdef WITH_UAENET_PCAP
case UAENET_PCAP:
if (uaenet_open (vsd, ndd, user, gotfunc, getfunc, promiscuous, mac)) {
netmode = ndd->type;
return 1;
}
return 0;
#endif
}
return 0;
}
void ethernet_close (struct netdriverdata *ndd, void *vsd)
{
if (!ndd)
return;
switch (ndd->type)
{
case UAENET_SLIRP:
case UAENET_SLIRP_INBOUND:
if (slirp_data) {
slirp_data = NULL;
uae_slirp_end ();
uae_slirp_cleanup ();
uae_sem_destroy (&slirp_sem1);
uae_sem_destroy (&slirp_sem2);
}
return;
#ifdef WITH_UAENET_PCAP
case UAENET_PCAP:
return uaenet_close (vsd);
#endif
}
}
void ethernet_enumerate_free (void)
{
#ifdef WITH_UAENET_PCAP
uaenet_enumerate_free ();
#endif
}
bool ethernet_enumerate (struct netdriverdata **nddp, int romtype)
{
int j;
struct netdriverdata *nd;
const TCHAR *name = NULL;
if (romtype) {
struct romconfig *rc = get_device_romconfig(&currprefs, romtype, 0);
name = ethernet_getselectionname(rc ? rc->device_settings : 0);
}
gui_flicker_led(LED_NET, 0, 0);
if (name) {
netmode = 0;
*nddp = NULL;
if (!_tcsicmp (slirpd.name, name))
*nddp = &slirpd;
if (!_tcsicmp (slirpd2.name, name))
*nddp = &slirpd2;
#ifdef WITH_UAENET_PCAP
if (*nddp == NULL)
*nddp = uaenet_enumerate (name);
#endif
if (*nddp) {
netmode = (*nddp)->type;
return true;
}
return false;
}
j = 0;
nddp[j++] = &slirpd;
nddp[j++] = &slirpd2;
#ifdef WITH_UAENET_PCAP
nd = uaenet_enumerate (NULL);
if (nd) {
int last = MAX_TOTAL_NET_DEVICES - 1 - j;
for (int i = 0; i < last; i++) {
if (nd[i].active)
nddp[j++] = &nd[i];
}
}
#endif
nddp[j] = NULL;
return true;
}
void ethernet_close_driver (struct netdriverdata *ndd)
{
switch (ndd->type)
{
case UAENET_SLIRP:
case UAENET_SLIRP_INBOUND:
return;
#ifdef WITH_UAENET_PCAP
case UAENET_PCAP:
return uaenet_close_driver (ndd);
#endif
}
netmode = 0;
}
int ethernet_getdatalenght (struct netdriverdata *ndd)
{
switch (ndd->type)
{
case UAENET_SLIRP:
case UAENET_SLIRP_INBOUND:
return sizeof (struct ethernet_data);
#ifdef WITH_UAENET_PCAP
case UAENET_PCAP:
return uaenet_getdatalenght ();
#endif
}
return 0;
}
bool ethernet_getmac(uae_u8 *m, const TCHAR *mac)
{
if (!mac)
return false;
if (_tcslen(mac) != 3 * 5 + 2)
return false;
for (int i = 0; i < 6; i++) {
TCHAR *endptr;
if (mac[0] == 0 || mac[1] == 0)
return false;
if (i < 5 && (mac[2] != '.' && mac[2] != ':'))
return false;
uae_u8 v = (uae_u8)_tcstol(mac, &endptr, 16);
mac += 3;
m[i] = v;
}
return true;
}