#define MAX_ASYNC_REQUESTS 200
#define MAX_OPEN_DEVICES 20
+#define DELAYED_DROPPED_PACKET_FRAMES 100
+
#define S2_START (CMD_NONSTD) // 9
#define S2_DEVICEQUERY (S2_START+ 0) // 9
#define S2_GETSTATIONADDRESS (S2_START+ 1) // 10
#define S2_CopyFromBuff32 (S2_Dummy + 7)
#define S2_DMACopyToBuff32 (S2_Dummy + 8)
#define S2_DMACopyFromBuff32 (S2_Dummy + 9)
+#define S2_DMACopyToBuff64 (S2_Dummy + 10)
+#define S2_DMACopyFromBuff64 (S2_Dummy + 11)
+#define S2_Log (S2_Dummy + 12)
#define SANA2_IOREQSIZE (32 + 4 + 4 + SANA2_MAX_ADDR_BYTES * 2 + 4 + 4 + 4 + 4)
struct s2packet *next;
uae_u8 *data;
int len;
+ int drop_start;
+ int drop_count;
};
static int uaenet_int_late;
while (tagpnext) {
uae_u32 tag = trap_get_long(ctx, tagpnext);
uae_u32 val = trap_get_long(ctx, tagpnext + 4);
+ if (log_net)
+ write_log(_T("%s:%d TAG %08x %08x\n"), getdevname(), unit, tag, val);
tagp = tagpnext;
tagpnext += 8;
switch (tag)
return s2p;
}
+static const TCHAR *dumphead(uae_u8 *d, int len)
+{
+ static TCHAR dumptxt[256];
+ uae_u16 type = (d[2 * ADDR_SIZE] << 8) | d[2 * ADDR_SIZE + 1];
+ _stprintf(dumptxt, _T("DST:%02X.%02X.%02X.%02X.%02X.%02X SRC:%02X.%02X.%02X.%02X.%02X.%02X E=%04X L=%d"),
+ d[0], d[1], d[2], d[3], d[4], d[5],
+ d[6], d[7], d[8], d[9], d[10], d[11],
+ type, len);
+ return dumptxt;
+}
+
static int handleread (TrapContext *ctx, struct priv_s2devstruct *pdev, struct s2devstruct *dev, uae_u8 *request, uaecptr arequest, uae_u8 *d, int len, int cmd)
{
uae_u8 flags = get_byte_host(request + 30);
}
if (!mc) {
if (log_net)
- write_log(_T("-> multicast filter rejected, CMD_READ, REQ=%08X LEN=%d\n"), arequest, len);
+ write_log(_T("-> %s multicast filter rejected, CMD_READ, REQ=%08X LEN=%d\n"), dumphead(d, len), arequest, len);
return 0;
}
}
if (cmd == CMD_READ) {
if (pdev->packetfilter && packetfilter (ctx, pdev->packetfilter, arequest, data2) == 0) {
if (log_net)
- write_log(_T("-> PacketFilter() rejected, CMD_READ, REQ=%08X LEN=%d\n"), arequest, len);
+ write_log(_T("-> %s PacketFilter() rejected, CMD_READ, REQ=%08X LEN=%d\n"), dumphead(d, len), arequest, len);
return 0;
}
}
put_long_host(request + 32, S2WERR_BUFF_ERROR);
put_byte_host(request + 31, S2ERR_NO_RESOURCES);
if (log_net)
- write_log(_T("-> CopyToBuff() rejected, CMD_READ, REQ=%08X LEN=%d\n"), arequest, len);
+ write_log(_T("-> %s CopyToBuff() rejected, CMD_READ, REQ=%08X LEN=%d\n"), dumphead(d, len), arequest, len);
}
return 1;
}
if (!dev->online)
return;
/* drop if bogus size */
- if (len < 20 || len >= dev->td->mtu + ETH_HEADER_SIZE + 2)
+ if (len < 20 || len >= dev->td->mtu + ETH_HEADER_SIZE + 2) {
+ if (log_net)
+ write_log(_T("<- invalid packet size %d\n"), len);
return;
+ }
/* drop if dst == broadcast and src == me */
if (isbroadcast (d) && !memcmp (d + 6, dev->td->mac, ADDR_SIZE))
return;
s2p = createreadpacket (dev, d, len);
if (log_net)
write_log (_T("<-DST:%02X.%02X.%02X.%02X.%02X.%02X SRC:%02X.%02X.%02X.%02X.%02X.%02X E=%04X L=%d P=%p\n"),
- d[0], d[1], d[2], d[3], d[4], d[5],
- d[6], d[7], d[8], d[9], d[10], d[11],
- type, len, s2p);
+ d[0], d[1], d[2], d[3], d[4], d[5],
+ d[6], d[7], d[8], d[9], d[10], d[11],
+ type, len, s2p);
uae_sem_wait (&async_sem);
if (!dev->readqueue) {
dev->readqueue = s2p;
uae_u16 packettype = get_long_host(request + 32 + 4);
struct s2packet *s2p;
- if (!pdev)
+ if (!pdev) {
+ if (log_net)
+ write_log(_T("-> createwritepacket() without device, REQ=%08X LEN=%d\n"), arequest, datalength);
return NULL;
+ }
if (!copyfrombuff (ctx, data, pdev->tempbuf, datalength, pdev->copyfrombuff)) {
if (log_net)
write_log(_T("-> CopyFromBuff() rejected, CMD_READ, REQ=%08X LEN=%d\n"), arequest, datalength);
memcpy(d, ars2p->s2p->data, *len);
if (log_net)
write_log (_T("->DST:%02X.%02X.%02X.%02X.%02X.%02X SRC:%02X.%02X.%02X.%02X.%02X.%02X E=%04X S=%d\n"),
- d[0], d[1], d[2], d[3], d[4], d[5],
- d[6], d[7], d[8], d[9], d[10], d[11],
- packettype, *len);
+ d[0], d[1], d[2], d[3], d[4], d[5],
+ d[6], d[7], d[8], d[9], d[10], d[11],
+ packettype, *len);
gotit = 1;
dev->packetssent++;
signalasync(dev->ctx, dev, ar, *len, 0);
goto end;
}
}
+ if (statdata == 0 && (command == S2_DEVICEQUERY || command == S2_GETTYPESTATS || command == S2_GETGLOBALSTATS || command == S2_GETSPECIALSTATS)) {
+ io_error = S2ERR_BAD_ARGUMENT;
+ wire_error = S2WERR_NULL_POINTER;
+ goto end;
+ }
switch (command)
{
{
uae_u8 statbuf[34];
int size = trap_get_long(ctx, statdata);
+ if (size < 8 || size >= 0x10000) {
+ io_error = S2ERR_BAD_ARGUMENT;
+ wire_error = S2WERR_BAD_STATDATA;
+ goto end;
+ }
if (size > 34)
size = 34;
put_long_host(statbuf + 4 , size);
}
end:
if (log_net && (io_error || wire_error))
- write_log (_T("-> %d (%d)\n"), io_error, wire_error);
+ write_log (_T("-> ERR %d (%d)\n"), io_error, wire_error);
put_long_host(request + 32, wire_error);
put_byte_host(request + 31, io_error);
return async;
case S2_GETSTATIONADDRESS:
case S2_TRACKTYPE:
case S2_UNTRACKTYPE:
+ case S2_ADDMULTICASTADDRESS:
+ case S2_ADDMULTICASTADDRESSES:
+ case S2_DELMULTICASTADDRESS:
+ case S2_DELMULTICASTADDRESSES:
+ case S2_GETTYPESTATS:
+ case S2_GETGLOBALSTATS:
+ case S2_GETSPECIALSTATS:
return 1;
}
return 0;
}
-static int dev_canquick (TrapContext *ctx, struct s2devstruct *dev, uae_u8 *request)
+static int dev_canquick (struct s2devstruct *dev, uae_u8 *request)
{
uae_u32 command = get_word_host(request + 28);
return dev_can_quick (command);
{
uae_u32 cmd = get_word_host(src + 28);
uae_u16 len = get_word_host(src + 18);
- if (len < 30)
+
+ if (len < 8)
return;
- len -= 30;
- src += 30;
- dst += 30;
+ // IORequest ln_Type needs to be copied
+ len -= 8;
+ src += 8;
+ dst += 8;
if (cmd == S2_BROADCAST || cmd == S2_MULTICAST || cmd == S2_READORPHAN || cmd == CMD_WRITE || cmd == CMD_READ || cmd == S2_GETSTATIONADDRESS) {
// Copy:
+ // IORequest
// io_Flags, ioError
// ios2_WireError, ios2_PacketType
// ios2_SrcAddr, ios2_DstAddr
// ios2_DataLength
- if (len > 1 + 1 + 4 + 4 + 2 * SANA2_MAX_ADDR_BYTES + 4)
- len = 1 + 1 + 4 + 4 + 2 * SANA2_MAX_ADDR_BYTES + 4;
+ if (len > SANA2_IOREQSIZE - (8 + 3 * 4))
+ len = SANA2_IOREQSIZE - (8 + 3 * 4);
trap_put_bytes(ctx, src, dst, len);
} else {
// Copy:
+ // IORequest
// io_Flags, ioError
// ios2_WireError
- trap_put_bytes(ctx, src, dst, 1 + 1 + 4);
+ trap_put_bytes(ctx, src, dst, (32 - 8) + 1 + 1 + 4);
}
}
goto err;
}
- if ((flags & 1) && dev_canquick (ctx, dev, request)) {
+ if ((flags & 1) && dev_canquick (dev, request)) {
if (dev_do_io(ctx, dev, request, arequest, 1))
write_log (_T("%s: command %d bug with IO_QUICK\n"), SANA2NAME, command);
err = get_byte_host(request + 31);
return 0;
}
+static void resetpackettimer(struct s2packet *p)
+{
+ while (p) {
+ p->drop_start = 0;
+ p->drop_count = 0;
+ p = p->next;
+ }
+}
+
static int uaenet_int_handler2(TrapContext *ctx)
{
int i, j;
- int gotit;
struct asyncreq *ar;
bool irq = false;
- for (i = 0; i < MAX_OPEN_DEVICES; i++)
+ for (i = 0; i < MAX_OPEN_DEVICES; i++) {
pdevst[i].tmp = 0;
+ }
for (i = 0; i < MAX_TOTAL_NET_DEVICES; i++) {
struct s2devstruct *dev = &devst[i];
p = dev->readqueue;
type = (p->data[2 * ADDR_SIZE] << 8) | p->data[2 * ADDR_SIZE + 1];
ar = dev->ar;
- gotit = 0;
while (ar) {
if (!ar->ready) {
uaecptr arequest = ar->arequest;
struct priv_s2devstruct *pdev = getps2devstruct(ctx, request, arequest);
if (pdev && pdev->tmp == 0) {
if (handleread (ctx, pdev, dev, request, arequest, p->data, p->len, command)) {
- if (log_net)
- write_log (_T("-> %p Accepted, CMD_READ, REQ=%08X LEN=%d\n"), p, arequest, p->len);
+ if (log_net) {
+ write_log (_T("-> %s Accepted, CMD_READ, REQ=%08X LEN=%d D=%d\n"), dumphead(p->data, p->len), arequest, p->len, p->drop_start ? 1 : 0);
+ }
ar->ready = 1;
uae_sem_wait(&pipe_sem);
trap_set_background(ctx);
dev->packetsreceived++;
pdev->tmp = 1;
dev->readqueue = dev->readqueue->next;
+ resetpackettimer(dev->readqueue);
freepacket(p);
return -1;
} else {
struct priv_s2devstruct *pdev = getps2devstruct(ctx, request, arequest);
if (pdev && pdev->tmp <= 0) {
if (log_net)
- write_log (_T("-> %p Accepted, S2_READORPHAN, REQ=%08X LEN=%d\n"), p, arequest, p->len);
+ write_log (_T("-> %s Accepted, S2_READORPHAN, REQ=%08X D=%d\n"), dumphead(p->data, p->len), arequest, p->drop_start ? 1 : 0);
handleread (ctx, pdev, dev, request, arequest, p->data, p->len, command);
ar->ready = 1;
uae_sem_wait(&pipe_sem);
uae_sem_post(&pipe_sem);
dev->packetsreceived++;
dev->unknowntypesreceived++;
- gotit = 1;
pdev->tmp = 1;
dev->readqueue = dev->readqueue->next;
+ resetpackettimer(dev->readqueue);
freepacket(p);
return -1;
}
}
ar = ar->next;
}
- if (!gotit) {
- if (log_net)
- write_log (_T("-> %p packet dropped, LEN=%d\n"), p, p->len);
- for (j = 0; j < MAX_OPEN_DEVICES; j++) {
- if (pdevst[j].unit == dev->unit) {
- if (pdevst[j].tracks[type])
- pdevst[j].packetsdropped++;
- }
+ if (p->drop_start == 0 || p->drop_count - p->drop_start < DELAYED_DROPPED_PACKET_FRAMES) {
+ // we got packet but there was no readers, lets wait a bit before dropping it.
+ if (log_net && p->drop_start == 0) {
+ write_log(_T("-> %s No readers, queued for dropping\n"), dumphead(p->data, p->len));
+ }
+ while (p) {
+ if (p->drop_start == 0)
+ p->drop_start = timeframes;
+ p->drop_count = timeframes;
+ p = p->next;
+ }
+ break;
+ }
+ if (log_net) {
+ write_log (_T("-> %s packet dropped, CNT=%d/%d:%d\n"), dumphead(p->data, p->len), p->drop_start, p->drop_count, p->drop_count - p->drop_start);
+ }
+ for (j = 0; j < MAX_OPEN_DEVICES; j++) {
+ if (pdevst[j].unit == dev->unit) {
+ if (pdevst[j].tracks[type])
+ pdevst[j].packetsdropped++;
}
}
dev->readqueue = dev->readqueue->next;
- freepacket (p);
+ freepacket(p);
}
} else {
while (dev->readqueue) {