1 #include "sysconfig.h"
2 #include "sysdeps.h"
3 
4 #include "ethernet.h"
5 #ifdef _WIN32
6 #ifdef FSUAE
7 #else
8 #include "win32_uaenet.h"
9 #endif
10 #endif
11 #include "threaddep/thread.h"
12 #include "options.h"
13 #include "sana2.h"
14 #include "uae/slirp.h"
15 
16 #ifndef HAVE_INET_ATON
inet_aton(const char * cp,struct in_addr * ia)17 static int inet_aton(const char *cp, struct in_addr *ia)
18 {
19 	uint32_t addr = inet_addr(cp);
20 	if (addr == 0xffffffff)
21 		return 0;
22 	ia->s_addr = addr;
23 	return 1;
24 }
25 #endif
26 
27 struct ethernet_data
28 {
29 	ethernet_gotfunc *gotfunc;
30 	ethernet_getfunc *getfunc;
31 	void *userdata;
32 };
33 
34 #define SLIRP_PORT_OFFSET 0
35 
36 static const int slirp_ports[] = { 21, 22, 23, 80, 0 };
37 
38 static struct ethernet_data *slirp_data;
39 static bool slirp_inited;
40 uae_sem_t slirp_sem1, slirp_sem2;
41 static int netmode;
42 
43 static struct netdriverdata slirpd =
44 {
45 	UAENET_SLIRP,
46 	_T("slirp"), _T("SLIRP User Mode NAT"),
47 	1500,
48 	{ 0x00,0x00,0x00,50,51,52 },
49 	1
50 };
51 static struct netdriverdata slirpd2 =
52 {
53 	UAENET_SLIRP_INBOUND,
54 	_T("slirp_inbound"), _T("SLIRP + Open ports (21-23,80)"),
55 	1500,
56 	{ 0x00,0x00,0x00,50,51,52 },
57 	1
58 };
59 
slirp_output(const uint8_t * pkt,int pkt_len)60 void slirp_output (const uint8_t *pkt, int pkt_len)
61 {
62 	if (!slirp_data)
63 		return;
64 	uae_sem_wait (&slirp_sem1);
65 	slirp_data->gotfunc (slirp_data->userdata, pkt, pkt_len);
66 	uae_sem_post (&slirp_sem1);
67 }
68 
ethernet_trigger(struct netdriverdata * ndd,void * vsd)69 void ethernet_trigger (struct netdriverdata *ndd, void *vsd)
70 {
71 	if (!ndd)
72 		return;
73 	switch (ndd->type)
74 	{
75 #ifdef WITH_SLIRP
76 		case UAENET_SLIRP:
77 		case UAENET_SLIRP_INBOUND:
78 		{
79 			struct ethernet_data *ed = (struct ethernet_data*)vsd;
80 			if (slirp_data) {
81 				uae_u8 pkt[4000];
82 				int len = sizeof pkt;
83 				int v;
84 				uae_sem_wait (&slirp_sem1);
85 				v = slirp_data->getfunc(ed->userdata, pkt, &len);
86 				uae_sem_post (&slirp_sem1);
87 				if (v) {
88 					uae_sem_wait (&slirp_sem2);
89 					uae_slirp_input(pkt, len);
90 					uae_sem_post (&slirp_sem2);
91 				}
92 			}
93 		}
94 		return;
95 #endif
96 #ifdef WITH_UAENET_PCAP
97 		case UAENET_PCAP:
98 		uaenet_trigger (vsd);
99 		return;
100 #endif
101 	}
102 }
103 
ethernet_open(struct netdriverdata * ndd,void * vsd,void * user,ethernet_gotfunc * gotfunc,ethernet_getfunc * getfunc,int promiscuous)104 int ethernet_open (struct netdriverdata *ndd, void *vsd, void *user, ethernet_gotfunc *gotfunc, ethernet_getfunc *getfunc, int promiscuous)
105 {
106 	switch (ndd->type)
107 	{
108 #ifdef WITH_SLIRP
109 		case UAENET_SLIRP:
110 		case UAENET_SLIRP_INBOUND:
111 		{
112 			struct ethernet_data *ed = (struct ethernet_data*)vsd;
113 			ed->gotfunc = gotfunc;
114 			ed->getfunc = getfunc;
115 			ed->userdata = user;
116 			slirp_data = ed;
117 			uae_sem_init (&slirp_sem1, 0, 1);
118 			uae_sem_init (&slirp_sem2, 0, 1);
119 			uae_slirp_init();
120 			for (int i = 0; i < MAX_SLIRP_REDIRS; i++) {
121 				struct slirp_redir *sr = &currprefs.slirp_redirs[i];
122 				if (sr->proto) {
123 					struct in_addr a;
124 					if (sr->srcport == 0) {
125 					    inet_aton("10.0.2.15", &a);
126 						uae_slirp_redir (0, sr->dstport, a, sr->dstport);
127 					} else {
128 #ifdef HAVE_STRUCT_IN_ADDR_S_UN
129 						a.S_un.S_addr = sr->addr;
130 #else
131 						a.s_addr = sr->addr;
132 #endif
133 						uae_slirp_redir (sr->proto == 1 ? 0 : 1, sr->dstport, a, sr->srcport);
134 					}
135 				}
136 			}
137 			if (ndd->type == UAENET_SLIRP_INBOUND) {
138 				struct in_addr a;
139 			    inet_aton("10.0.2.15", &a);
140 				for (int i = 0; slirp_ports[i]; i++) {
141 					int port = slirp_ports[i];
142 					int j;
143 					for (j = 0; j < MAX_SLIRP_REDIRS; j++) {
144 						struct slirp_redir *sr = &currprefs.slirp_redirs[j];
145 						if (sr->proto && sr->dstport == port)
146 							break;
147 					}
148 					if (j == MAX_SLIRP_REDIRS)
149 						uae_slirp_redir (0, port + SLIRP_PORT_OFFSET, a, port);
150 				}
151 			}
152 			netmode = ndd->type;
153 			uae_slirp_start ();
154 		}
155 		return 1;
156 #endif
157 #ifdef WITH_UAENET_PCAP
158 		case UAENET_PCAP:
159 		if (uaenet_open (vsd, ndd, user, gotfunc, getfunc, promiscuous)) {
160 			netmode = ndd->type;
161 			return 1;
162 		}
163 		return 0;
164 #endif
165 	}
166 	return 0;
167 }
168 
ethernet_close(struct netdriverdata * ndd,void * vsd)169 void ethernet_close (struct netdriverdata *ndd, void *vsd)
170 {
171 	if (!ndd)
172 		return;
173 	switch (ndd->type)
174 	{
175 #ifdef WITH_SLIRP
176 		case UAENET_SLIRP:
177 		case UAENET_SLIRP_INBOUND:
178 		if (slirp_data) {
179 			slirp_data = NULL;
180 			uae_slirp_end ();
181 			uae_slirp_cleanup ();
182 			uae_sem_destroy (&slirp_sem1);
183 			uae_sem_destroy (&slirp_sem2);
184 		}
185 		return;
186 #endif
187 #ifdef WITH_UAENET_PCAP
188 		case UAENET_PCAP:
189 		return uaenet_close (vsd);
190 #endif
191 	}
192 }
193 
ethernet_enumerate_free(void)194 void ethernet_enumerate_free (void)
195 {
196 #ifdef WITH_UAENET_PCAP
197 	uaenet_enumerate_free ();
198 #endif
199 }
200 
ethernet_enumerate(struct netdriverdata ** nddp,const TCHAR * name)201 bool ethernet_enumerate (struct netdriverdata **nddp, const TCHAR *name)
202 {
203 	int j;
204 	struct netdriverdata *nd;
205 	if (name) {
206 		netmode = 0;
207 		*nddp = NULL;
208 		if (!_tcsicmp (slirpd.name, name))
209 			*nddp = &slirpd;
210 		if (!_tcsicmp (slirpd2.name, name))
211 			*nddp = &slirpd2;
212 #ifdef WITH_UAENET_PCAP
213 		if (*nddp == NULL)
214 			*nddp = uaenet_enumerate (name);
215 #endif
216 		if (*nddp) {
217 			netmode = (*nddp)->type;
218 			return true;
219 		}
220 		return false;
221 	}
222 	j = 0;
223 	nddp[j++] = &slirpd;
224 	nddp[j++] = &slirpd2;
225 #ifdef WITH_UAENET_PCAP
226 	nd = uaenet_enumerate (NULL);
227 	if (nd) {
228 		for (int i = 0; i < MAX_TOTAL_NET_DEVICES; i++) {
229 			if (nd[i].active)
230 				nddp[j++] = &nd[i];
231 		}
232 	}
233 #endif
234 	nddp[j] = NULL;
235 	return true;
236 }
237 
ethernet_close_driver(struct netdriverdata * ndd)238 void ethernet_close_driver (struct netdriverdata *ndd)
239 {
240 	switch (ndd->type)
241 	{
242 		case UAENET_SLIRP:
243 		case UAENET_SLIRP_INBOUND:
244 		return;
245 #ifdef WITH_UAENET_PCAP
246 		case UAENET_PCAP:
247 		return uaenet_close_driver (ndd);
248 #endif
249 	}
250 	netmode = 0;
251 }
252 
ethernet_getdatalenght(struct netdriverdata * ndd)253 int ethernet_getdatalenght (struct netdriverdata *ndd)
254 {
255 	switch (ndd->type)
256 	{
257 		case UAENET_SLIRP:
258 		case UAENET_SLIRP_INBOUND:
259 		return sizeof (struct ethernet_data);
260 #ifdef WITH_UAENET_PCAP
261 		case UAENET_PCAP:
262 		return uaenet_getdatalenght ();
263 #endif
264 	}
265 	return 0;
266 }
267