main megawifi.c
  1#include <stdlib.h>
  2#include <stdint.h>
  3#include <string.h>
  4#include <sys/types.h>
  5#include <sys/socket.h>
  6#include <unistd.h>
  7#include <netinet/in.h>
  8#include <errno.h>
  9#include <fcntl.h>
 10#include "genesis.h"
 11#include "net.h"
 12
 13enum {
 14	TX_IDLE,
 15	TX_LEN1,
 16	TX_LEN2,
 17	TX_PAYLOAD,
 18	TX_WAIT_ETX
 19};
 20#define STX 0x7E
 21#define ETX 0x7E
 22#define MAX_RECV_SIZE 1440
 23
 24#define E(N) N
 25enum {
 26#include "mw_commands.c"
 27	CMD_ERROR = 255
 28};
 29#undef E
 30#define E(N) #N
 31static const char *cmd_names[] = {
 32#include "mw_commands.c"
 33	[255] = "CMD_ERROR"
 34};
 35
 36#ifndef MSG_NOSIGNAL
 37#define MSG_NOSIGNAL 0
 38#endif
 39
 40enum {
 41	STATE_IDLE=1,
 42	STATE_AP_JOIN,
 43	STATE_SCAN,
 44	STATE_READY,
 45	STATE_TRANSPARENT
 46};
 47
 48#define FLAG_ONLINE 
 49
 50typedef struct {
 51	uint32_t transmit_bytes;
 52	uint32_t expected_bytes;
 53	uint32_t receive_bytes;
 54	uint32_t receive_read;
 55	int      sock_fds[15];
 56	uint16_t channel_flags;
 57	uint8_t  channel_state[15];
 58	uint8_t  scratchpad;
 59	uint8_t  transmit_channel;
 60	uint8_t  transmit_state;
 61	uint8_t  module_state;
 62	uint8_t  flags;
 63	uint8_t  transmit_buffer[4096];
 64	uint8_t  receive_buffer[4096];
 65} megawifi;
 66
 67static megawifi *get_megawifi(void *context)
 68{
 69	m68k_context *m68k = context;
 70	genesis_context *gen = m68k->system;
 71	if (!gen->extra) {
 72		gen->extra = calloc(1, sizeof(megawifi));
 73		megawifi *mw = gen->extra;
 74		mw->module_state = STATE_IDLE;
 75		for (int i = 0; i < 15; i++)
 76		{
 77			mw->sock_fds[i] = -1;
 78		}
 79	}
 80	return gen->extra;
 81}
 82
 83static void mw_putc(megawifi *mw, uint8_t v)
 84{
 85	if (mw->receive_bytes == sizeof(mw->receive_buffer)) {
 86		return;
 87	}
 88	mw->receive_buffer[mw->receive_bytes++] = v;
 89}
 90
 91static void mw_set(megawifi *mw, uint8_t val, uint32_t count)
 92{
 93	if (count + mw->receive_bytes > sizeof(mw->receive_buffer)) {
 94		count = sizeof(mw->receive_buffer) - mw->receive_bytes;
 95	}
 96	memset(mw->receive_buffer + mw->receive_bytes, val, count);
 97	mw->receive_bytes += count;
 98}
 99
100static void mw_copy(megawifi *mw, const uint8_t *src, uint32_t count)
101{
102	if (count + mw->receive_bytes > sizeof(mw->receive_buffer)) {
103		count = sizeof(mw->receive_buffer) - mw->receive_bytes;
104	}
105	memcpy(mw->receive_buffer + mw->receive_bytes, src, count);
106	mw->receive_bytes += count;
107}
108
109static void mw_puts(megawifi *mw, char *s)
110{
111	uint32_t len = strlen(s);
112	if ((mw->receive_bytes + len) > sizeof(mw->receive_buffer)) {
113		return;
114	}
115	memcpy(mw->receive_buffer + mw->receive_bytes, s, len);
116	mw->receive_bytes += len;
117}
118
119static void poll_socket(megawifi *mw, uint8_t channel)
120{
121	if (mw->sock_fds[channel] < 0) {
122		return;
123	}
124	if (mw->channel_state[channel] == 1) {
125		int res = accept(mw->sock_fds[channel], NULL, NULL);
126		if (res >= 0) {
127			close(mw->sock_fds[channel]);
128			fcntl(res, F_SETFL, O_NONBLOCK);
129			mw->sock_fds[channel] = res;
130			mw->channel_state[channel] = 2;
131			mw->channel_flags |= 1 << (channel + 1);
132		} else if (errno != EAGAIN && errno != EWOULDBLOCK) {
133			close(mw->sock_fds[channel]);
134			mw->channel_state[channel] = 0;
135			mw->channel_flags |= 1 << (channel + 1);
136		}
137	} else if (mw->channel_state[channel] == 2 && mw->receive_bytes < sizeof(mw->receive_buffer) - 4) {
138		size_t max = sizeof(mw->receive_buffer) - 4 - mw->receive_bytes;
139		if (max > MAX_RECV_SIZE) {
140			max = MAX_RECV_SIZE;
141		}
142		int bytes = recv(mw->sock_fds[channel], mw->receive_buffer + mw->receive_bytes + 3, max, 0);
143		if (bytes > 0) {
144			mw_putc(mw, STX);
145			mw_putc(mw, bytes >> 8 | (channel+1) << 4);
146			mw_putc(mw, bytes);
147			mw->receive_bytes += bytes;
148			mw_putc(mw, ETX);
149			//should this set the channel flag?
150		} else if (bytes < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
151			close(mw->sock_fds[channel]);
152			mw->channel_state[channel] = 0;
153			mw->channel_flags |= 1 << (channel + 1);
154		}
155	}
156}
157
158static void poll_all_sockets(megawifi *mw)
159{
160	for (int i = 0; i < 15; i++)
161	{
162		poll_socket(mw, i);
163	}
164}
165
166static void start_reply(megawifi *mw, uint8_t cmd)
167{
168	mw_putc(mw, STX);
169	//reserve space for length
170	mw->receive_bytes += 2;
171	//cmd
172	mw_putc(mw, 0);
173	mw_putc(mw, cmd);
174	//reserve space for length
175	mw->receive_bytes += 2;
176}
177
178static void end_reply(megawifi *mw)
179{
180	uint32_t len = mw->receive_bytes - 3;
181	//LSD packet length
182	mw->receive_buffer[1] = len >> 8;
183	mw->receive_buffer[2] = len;
184	//command length
185	len -= 4;
186	mw->receive_buffer[5] = len >> 8;
187	mw->receive_buffer[6] = len;
188	mw_putc(mw, ETX);
189}
190
191static void process_packet(megawifi *mw)
192{
193	if (mw->transmit_channel == 0) {
194		uint32_t command = mw->transmit_buffer[0] << 8 | mw->transmit_buffer[1];
195		uint32_t size = mw->transmit_buffer[2] << 8 | mw->transmit_buffer[3];
196		if (size > mw->transmit_bytes - 4) {
197			size = mw->transmit_bytes - 4;
198		}
199		int orig_receive_bytes = mw->receive_bytes;
200		switch (command)
201		{
202		case CMD_VERSION:
203			start_reply(mw, CMD_OK);
204			mw_putc(mw, 1);
205			mw_putc(mw, 0);
206			mw_puts(mw, "blastem");
207			end_reply(mw);
208			break;
209		case CMD_ECHO:
210			mw->receive_bytes = mw->transmit_bytes;
211			memcpy(mw->receive_buffer, mw->transmit_buffer, mw->transmit_bytes);
212			break;
213		case CMD_IP_CURRENT: {
214			iface_info i;
215			if (get_host_address(&i)) {
216				start_reply(mw, CMD_OK);
217				//config number and reserved bytes
218				mw_set(mw, 0, 4);
219				//ip
220				mw_copy(mw, i.ip, sizeof(i.ip));
221				//net mask
222				mw_copy(mw, i.net_mask, sizeof(i.net_mask));
223				//gateway guess
224				mw_putc(mw, i.ip[0] & i.net_mask[0]);
225				mw_putc(mw, i.ip[1] & i.net_mask[1]);
226				mw_putc(mw, i.ip[2] & i.net_mask[2]);
227				mw_putc(mw, (i.ip[3] & i.net_mask[3]) + 1);
228				//dns
229				static const uint8_t localhost[] = {127,0,0,1};
230				mw_copy(mw, localhost, sizeof(localhost));
231				mw_copy(mw, localhost, sizeof(localhost));
232				
233			} else {
234				start_reply(mw, CMD_ERROR);
235			}
236			end_reply(mw);
237			break;
238		}
239		case CMD_AP_JOIN:
240			mw->module_state = STATE_READY;
241			start_reply(mw, CMD_OK);
242			end_reply(mw);
243			break;
244		case CMD_TCP_BIND:{
245			if (size < 7){
246				start_reply(mw, CMD_ERROR);
247				end_reply(mw);
248				break;
249			}
250			uint8_t channel = mw->transmit_buffer[10];
251			if (!channel || channel > 15) {
252				start_reply(mw, CMD_ERROR);
253				end_reply(mw);
254				break;
255			}
256			channel--;
257			if (mw->sock_fds[channel] >= 0) {
258				close(mw->sock_fds[channel]);
259			}
260			mw->sock_fds[channel] = socket(AF_INET, SOCK_STREAM, 0);
261			if (mw->sock_fds[channel] < 0) {
262				start_reply(mw, CMD_ERROR);
263				end_reply(mw);
264				break;
265			}
266			int value = 1;
267			setsockopt(mw->sock_fds[channel], SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value));
268			struct sockaddr_in bind_addr;
269			memset(&bind_addr, 0, sizeof(bind_addr));
270			bind_addr.sin_family = AF_INET;
271			bind_addr.sin_port = htons(mw->transmit_buffer[8] << 8 | mw->transmit_buffer[9]);
272			if (bind(mw->sock_fds[channel], (struct sockaddr *)&bind_addr, sizeof(bind_addr)) != 0) {
273				close(mw->sock_fds[channel]);
274				mw->sock_fds[channel] = -1;
275				start_reply(mw, CMD_ERROR);
276				end_reply(mw);
277				break;
278			}
279			int res = listen(mw->sock_fds[channel], 2);
280			start_reply(mw, res ? CMD_ERROR : CMD_OK);
281			if (res) {
282				close(mw->sock_fds[channel]);
283				mw->sock_fds[channel] = -1;
284			} else {
285				mw->channel_flags |= 1 << (channel + 1);
286				mw->channel_state[channel] = 1;
287				fcntl(mw->sock_fds[channel], F_SETFL, O_NONBLOCK);
288			}
289			end_reply(mw);
290			break;
291		}
292		case CMD_SOCK_STAT: {
293			uint8_t channel = mw->transmit_buffer[4];
294			if (!channel || channel > 15) {
295				start_reply(mw, CMD_ERROR);
296				end_reply(mw);
297				break;
298			}
299			mw->channel_flags &= ~(1 << channel);
300			channel--;
301			poll_socket(mw, channel);
302			start_reply(mw, CMD_OK);
303			mw_putc(mw, mw->channel_state[channel]);
304			end_reply(mw);
305			break;
306		}
307		case CMD_SYS_STAT:
308			poll_all_sockets(mw);
309			start_reply(mw, CMD_OK);
310			mw_putc(mw, mw->module_state);
311			mw_putc(mw, mw->flags);
312			mw_putc(mw, mw->channel_flags >> 8);
313			mw_putc(mw, mw->channel_flags);
314			end_reply(mw);
315			break;
316		default:
317			printf("Unhandled MegaWiFi command %s(%d) with length %X\n", cmd_names[command], command, size);
318			break;
319		}
320	} else if (mw->sock_fds[mw->transmit_channel - 1] >= 0 && mw->channel_state[mw->transmit_channel - 1] == 2) {
321		uint8_t channel = mw->transmit_channel - 1;
322		int sent = send(mw->sock_fds[channel], mw->transmit_buffer, mw->transmit_bytes, MSG_NOSIGNAL);
323		if (sent < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
324			close(mw->sock_fds[channel]);
325			mw->sock_fds[channel] = -1;
326			mw->channel_state[channel] = 0;
327			mw->channel_flags |= 1 << mw->transmit_channel;
328		} else if (sent < mw->transmit_bytes) {
329			//TODO: save this data somewhere so it can be sent in poll_socket
330			printf("Sent %d bytes on channel %d, but %d were requested\n", sent, mw->transmit_channel, mw->transmit_bytes);
331		}
332	} else {
333		printf("Unhandled receive of MegaWiFi data on channel %d\n", mw->transmit_channel);
334	}
335	mw->transmit_bytes = mw->expected_bytes = 0;
336}
337
338void *megawifi_write_b(uint32_t address, void *context, uint8_t value)
339{
340	if (!(address & 1)) {
341		return context;
342	}
343	megawifi *mw = get_megawifi(context);
344	address = address >> 1 & 7;
345	switch (address)
346	{
347	case 0:
348		switch (mw->transmit_state)
349		{
350		case TX_IDLE:
351			if (value == STX) {
352				mw->transmit_state = TX_LEN1;
353			}
354			break;
355		case TX_LEN1:
356			mw->transmit_channel = value >> 4;
357			mw->expected_bytes = value << 8 & 0xF00;
358			mw->transmit_state = TX_LEN2;
359			break;
360		case TX_LEN2:
361			mw->expected_bytes |= value;
362			mw->transmit_state = TX_PAYLOAD;
363			break;
364		case TX_PAYLOAD:
365			mw->transmit_buffer[mw->transmit_bytes++] = value;
366			if (mw->transmit_bytes == mw->expected_bytes) {
367				mw->transmit_state = TX_WAIT_ETX;
368			}
369			break;
370		case TX_WAIT_ETX:
371			if (value == ETX) {
372				mw->transmit_state = TX_IDLE;
373				process_packet(mw);
374			}
375			break;
376		}
377		break;
378	case 7:
379		mw->scratchpad = value;
380		break;
381	default:
382		printf("Unhandled write to MegaWiFi UART register %X: %X\n", address, value);
383	}
384	return context;
385}
386
387void *megawifi_write_w(uint32_t address, void *context, uint16_t value)
388{
389	return megawifi_write_b(address | 1, context, value);
390}
391
392uint8_t megawifi_read_b(uint32_t address, void *context)
393{
394	
395	if (!(address & 1)) {
396		return 0xFF;
397	}
398	megawifi *mw = get_megawifi(context);
399	address = address >> 1 & 7;
400	switch (address)
401	{
402	case 0:
403		poll_all_sockets(mw);
404		if (mw->receive_read < mw->receive_bytes) {
405			uint8_t ret = mw->receive_buffer[mw->receive_read++];
406			if (mw->receive_read == mw->receive_bytes) {
407				mw->receive_read = mw->receive_bytes = 0;
408			}
409			return ret;
410		}
411		return 0xFF;
412	case 5:
413		poll_all_sockets(mw);
414		//line status
415		return 0x60 | (mw->receive_read < mw->receive_bytes);
416	case 7:
417		return mw->scratchpad;
418	default:
419		printf("Unhandled read from MegaWiFi UART register %X\n", address);
420		return 0xFF;
421	}
422}
423
424uint16_t megawifi_read_w(uint32_t address, void *context)
425{
426	return 0xFF00 | megawifi_read_b(address | 1, context);
427}