Discussion:
Packet driver - ARP packets come in too fast !
(too old to reply)
R.Wieser
2019-10-11 13:32:27 UTC
Permalink
Hello all,

I'm trying to communicate from a DOS 5 machine with one running Windows,
using a packet driver. To find my target 'puter I do an UDP broadcast for
a certain port.

The problem is that both my router as well as the targetted 'puter respond
with ARP request messages, and that my DOS 'puter is simply too slow to be
able to discard the routers ARP message (which is send to the broadcast IP),
and as a result drops the ARP message from the targetted 'puter. Hence the
connection fails

I already got the idea to create multiple ARP request buffers, but than
realized that that would just push the problem a bit further away - if
multiple 'puters respond I could easily run outof ARP buffers ...

I'm sure that this problem has been solved before, but my google-fu isn't
strong enough to find it. In other words: Does anyone have an idea how
this problem is normally handled ?

Regards,
Rudy Wieser
Mateusz Viste
2019-10-11 13:50:45 UTC
Permalink
Post by R.Wieser
The problem is that both my router as well as the targetted 'puter
respond with ARP request messages, and that my DOS 'puter is simply
too slow to be able to discard the routers ARP message (which is send
to the broadcast IP), and as a result drops the ARP message from the
targetted 'puter. Hence the connection fails
(...)
I'm sure that this problem has been solved before, but my google-fu
isn't strong enough to find it. In other words: Does anyone have an
idea how this problem is normally handled ?
What does your pktdrvr receiving routine looks like?

It's probably your pktdrvr receiving routine that drops the extra
frame, not the hardware. Perhaps because you only have buffer space for
a single frame? In any case, within your pktdrvr routine you should be
able to queue incoming packets in some kind of a list or ring, so the
application can unqueue them one by one when it has spare time.

Mateusz
R.Wieser
2019-10-11 15:23:41 UTC
Permalink
Mateusz,
Post by Mateusz Viste
It's probably your pktdrvr receiving routine that drops the
extra frame, not the hardware.
Indeed it does. It puts the received packet in a buffer, and exits the
callback routine. Another routine monitors if there is a packet, and if so
works on it. As long as the buffer is occupied all further packets are
(have to be) dropped.
Post by Mateusz Viste
Perhaps because you only have buffer space for a single frame?
:-) See above.
Post by Mateusz Viste
In any case, within your pktdrvr routine you should be able
able to queue incoming packets in some kind of a list or ring, so
the application can unqueue them one by one when it has spare
time.
I've been thinking of that too, but than what is large enough for such a
ring 4 blocks ? 40 ? I've got rather little information to go on.

Bottom line, I've been trying to create a solution pretty-much only looking
at the v1.11 packet driver specification. And although I've found a number
of programs also working with that API I've not been able to find a
description of /how/ they work (which means that all I can do is to look at
the code and try to figure out what the programmer was thinking of when he
wrote it - not all that easy).

And maybe a better question: Am I allowed , in the second callback (set by
AH=2 ) and before exiting it, to 1) take my time 2) send a packet back
(creating a de-facto hold-off for the network card - assuming here it has
some buffering itself).

Regards,
Rudy Wieser
Herbert Kleebauer
2019-10-11 17:38:00 UTC
Permalink
Post by R.Wieser
Post by Mateusz Viste
It's probably your pktdrvr receiving routine that drops the
extra frame, not the hardware.
Indeed it does. It puts the received packet in a buffer, and exits the
callback routine. Another routine monitors if there is a packet, and if so
works on it. As long as the buffer is occupied all further packets are
(have to be) dropped.
25 years ago I wrote an ethernet sniffer using the Packet Driver. I used
a 32kB ring buffer, the call back routine just stores the received data
in the ring buffer (if there is enough space available) and the main code
then reads from this ring buffer.

http://ikomi.de/pub/assembler/netzhack.zip
R.Wieser
2019-10-12 08:04:33 UTC
Permalink
Herbert,
25 years ago I wrote an ethernet sniffer using the Packet Driver. I used a
32kB ring buffer
As you will have it I remembered I did the same, using a linked list of
ethernet-block sized buffers. Just tok another look at it. Ah yes, the
drawback: the The "head" buffer could not become the same as the "tail"
buffer, effectivily wasting (after the data in it was handled) a full
buffer. :-\

I'll take a look at how your code handles it.

Regards
Rudy Wieser
Mateusz Viste
2019-10-11 18:10:17 UTC
Permalink
Rudy, sorry for not responding to your message properly - somehow my
news server misses it, so I had to get it through copy/paste via google
groups.
Post by R.Wieser
I've been thinking of that too, but than what is large enough for such
a ring 4 blocks ? 40 ? I've got rather little information to go on.
First of all, even with a 1-packet buffer it should work, as long as
you don't have some kind of broadcast storm on your LAN. Even if your
sluggish pktdrv callback drops an ARP request, the host that initiated
it will retry (typically 1s later, 2s later, etc up to few times), and
then you should get it. If you don't, then maybe you have another
problem going on with your code.

About the "right" size of your buffer - it depends on the real thing
you want to do. If it's about some kind of high performance data
transfers, then you will want send many packets in bursts, hence the
buffers should be big. If it's for a simple request/reply protocol,
then a 1-packet buffer should be good enough... That's the kind of
things you won't find an universal answer to on the internet. You have
to try different values empirically and benchmark each option within a
real-world scenario.

To avoid your protocol being polluted by ARP transactions (and
vice-versa) you might want to use separate buffers for each. You may
even go one step further, and use two different pktdrvr callback
routines for each, so you won't even have to look at the ethertype
yourself upon receival.
Post by R.Wieser
And maybe a better question: Am I allowed , in the second callback
(set by AH=2 ) and before exiting it, to 1) take my time 2) send a
packet back (creating a de-facto hold-off for the network card -
assuming here it has some buffering itself).
Taking your time is probably fine, the packet is already in the packet
driver's buffer so you won't loose it, but it also means that while you
take your time sipping tea you may loose newly incoming packets
(depending on how big the NIC's hw buffers are, and how the pktdrvr
communicates with it - ie. polling or int). So... Overall, I would
recommend keeping the callback as small and as fast as possible. You
also should take care not to use too much stack space there, you don't
know how much stack the pktdrvr routine has left.

As for sending a packet while being in the process of receiving one -
this is, as far as I know, undefined. I wouldn't do it, since I
wouldn't bet on the pktdrvr to be reentrant.

Mateusz
T. Ment
2019-10-11 18:56:31 UTC
Permalink
Post by Mateusz Viste
Rudy, sorry for not responding to your message properly - somehow my
news server misses it,
Your path:

eternal-september.org
gegeweb.org
usenet-fr.net
proxad.net
nnrp1-2.free.fr

eternal-september is at my end. Something rotten near you maybe.
Post by Mateusz Viste
so I had to get it through copy/paste via google groups.
eternal-september is free.
T. Ment
2019-10-11 19:43:36 UTC
Permalink
For the time being I switched to aioe.org myself. I will consider
eternal september if I find aioe unsatisfactory.
Sometimes my ISP's news server is allergic to messages posted through
aioe.org (many news server are, apparently).
I see AIOE doesn't require registration. Maybe that's why other servers
don't like it.

Eternal-september registration is easy. It requires your email address,
but they keep it secret. It's not visible in your post headers.
R.Wieser
2019-10-12 09:38:32 UTC
Permalink
T. Ment,
Post by T. Ment
I see AIOE doesn't require registration.
Eternal-september registration is easy. It requires your email
address, but they keep it secret.
A lot of other free services promise the same. For some odd reason I do
not readily believe them (anymore) ...

Regards,
Rudy Wieser
R.Wieser
2019-10-12 09:16:26 UTC
Permalink
Mateusz,
Post by Mateusz Viste
First of all, even with a 1-packet buffer it should work, as long
as you don't have some kind of broadcast storm on your LAN.
Thats what I thought too. But receiving five ARP packets (four from the
switch, one from the targetted 'puter) seems to be a bit too much: the one
packet I need gets dropped (Im counting those myself).
Post by Mateusz Viste
About the "right" size of your buffer - it depends on the real
thing you want to do. If it's about some kind of high performance
data transfers
Currently I already regard receiving-and-handling of the ARP packets I
actually need as "high performance" :-)
Post by Mateusz Viste
If it's for a simple request/reply protocol, then a 1-packet
buffer should be good enough...
Thats what I thought too, but alas ....
Post by Mateusz Viste
To avoid your protocol being polluted by ARP transactions (and
vice-versa) you might want to use separate buffers for each.
I've also been thinking of that. But being who I am I first want to figure
out why a simple (interfering, not for me) ARP request causes my program to
fail.
Post by Mateusz Viste
And maybe a better question: Am I allowed [snip]
Overall, I would recommend keeping the callback as
small and as fast as possible.
Yup, thats what I remembered (about interrupt routines) too. But being
able to handle ARP requests in the interrupt routine itself looked like
something I could try (shortest delay between receiving and responding).
Post by Mateusz Viste
As for sending a packet while being in the process of receiving
one - this is, as far as I know, undefined
I already assumed as much, but as I could not find anything about it ....


I just realized something: I'm polling for the buffer to be filled, and wait
for a few milisecs inbetween checks. That ofcourse creates a goof chance
that the first ethernet packet fills the buffer, and the next packet thus
gets dropped. Do you perhaps have a suggestion for a better "is it
available yet?" wait loop ?

Regards,
Rudy Wieser
Mateusz Viste
2019-10-12 09:52:51 UTC
Permalink
Post by R.Wieser
Post by Mateusz Viste
First of all, even with a 1-packet buffer it should work, as long
as you don't have some kind of broadcast storm on your LAN.
Thats what I thought too. But receiving five ARP packets (four from
the switch, one from the targetted 'puter) seems to be a bit too
much: the one packet I need gets dropped (Im counting those myself).
How come your router needs to send 4 ARP packets to you? It should
stop after the first one that you answer to. But perhaps you are not
answering to it, so it retries over and over, keeping your buffer busy?

And why is the targeted machine only sending a single ARP requests?
While not illegal, it's an odd behavior to fail after a single
unanswered ARP request. A "normal" ARP implementation will retry at
least a few times, but perhaps this computer you are referring to is
also some kind of minimalist system?
Post by R.Wieser
Currently I already regard receiving-and-handling of the ARP packets
I actually need as "high performance" :-)
Would you mind posting some code? It's really strange that you get into
such kind of troubles with only a couple of ARP frames.
Post by R.Wieser
Post by Mateusz Viste
If it's for a simple request/reply protocol, then a 1-packet
buffer should be good enough...
Thats what I thought too, but alas ....
I use single-packet buffers in both EtherDFS and ethflop, along with
some crude retransmission code. Works as expected (ie. well).
Post by R.Wieser
I just realized something: I'm polling for the buffer to be filled,
and wait for a few milisecs inbetween checks. That ofcourse creates
a goof chance that the first ethernet packet fills the buffer, and
the next packet thus gets dropped.
Do you wait also after you processed a packet? If yes, then you are
effectively shooting yourself in the foot. Waiting would seem tolerable
only if the check said "nothing available" - but even then, I wouldn't
wait myself, I'd just use a busy loop with an int 28h call. Since you
know you expect something, there is no point in waiting milliseconds -
the network latency between two hosts on a shared Ethernet segment is
often in the sub-milisecond range anyway.
Post by R.Wieser
Do you perhaps have a suggestion for a better "is it available
yet?" wait loop ?
Nothing of the sort, sorry. I would simply use a busy loop polling a
packet buffer, executing an int 28h when no packet is found in the
queue. In my (limited) experience, such approach works well even on
ancient 8086s.

Mateusz
R.Wieser
2019-10-12 11:12:13 UTC
Permalink
Mateusz,
Post by Mateusz Viste
How come your router needs to send 4 ARP packets to you? It should
stop after the first one that you answer to.
It doesn't. It sends it to the broadcast IP, with a zero MAC. And as such
there is, I think, nothing I should be answering to (but do correct me if
I'm wrong here).

But as my card has been configured to receieve MAC and broadcast (AH=0x14,
CX=0x0003) ... (Otherwise I cannot receive ARP packets)
Post by Mateusz Viste
And why is the targeted machine only sending a single ARP requests?
I can only guess to that I'm afraid. Maybe because it thinks the router
serves as a kind of server in this regard ? That would also explain why
the router is responding to a broadcast to a port it shouldn't have open.
Post by Mateusz Viste
but perhaps this computer you are referring to is
also some kind of minimalist system?
Its a standard XP sp3 setup. But I suppose nowerdays you /could/ refer to
that as a "minimalist system". :-)
Post by Mateusz Viste
Would you mind posting some code?
Sure, if you don't mind looking at Assembly. Which parts do you want to see
? And I hope you don't mind looking at a lot of experimental code ...

(some code added to the bottom)

But, as mentioned, I think the basic problem is that my polling (for the
buffer to be filled) is simply too slow. I can ofcourse speed it up, but
that would ofcourse cause my processor fans to go into a frenzy ....
Post by Mateusz Viste
It's really strange that you get into such kind of troubles
with only a couple of ARP frames.
The whould "trouble" is that a system (the router) is responding to a
request not ment for it. Unplugging the hub (which connects the DOS to the
XP 'puter) from the router makes all of it go away.
Post by Mateusz Viste
I use single-packet buffers in both EtherDFS and ethflop, along
with some crude retransmission code. Works as expected (ie. well).
In other words, it wouldn't be a bad idea to take a peek at it. :-)
Post by Mateusz Viste
Do you wait also after you processed a packet?
Yes. There is very little chance that a new ethernet packet arrives exactly
between the point that I release the buffer (after it has been handled in
full) and before the point where I start a wait (a few machine cycles). Or
are you perhaps thinking of a double-buffering, releasing the origional
receive buffer before even parsing its contents ?
Post by Mateusz Viste
executing an int 28h when no packet is found in the queue.
I could try that I suppose. But as I have zero idea when (on what
conditions) that call returns ... I don't really like that.

But ... now you've mentioned it (and I'm stuck anyway :-) ) the time has
come to try it. Looking in RBIL I see SS:SP mentioned as having to(?) point
to the "top of MS-DOS stack for I/O functions". Any remarks to that, or
can I just keep it inside my program ?

Nope, doesn't seem to work all that well. Still seeing "that one
packet"(tm) being dropped more often than not.

Regards,
Rudy Wieser

[[[ callback: Receiving the ethernet packet

;----------------------------
CBOnReceive proc
cmp ax,0001h ;Second Call-back ?
je @@OnRcvDataReady ;Yes

cmp [cs:gRcvSiz],0000h ;Buffer occupied ?
jne @@OnRcvDiscard ;Yes: Discard data

cmp cx,size gbRcvBuf ;Packet too big ?
ja @@OnRcvDiscard ;Yes: Discard data

mov di,cs ;Return location and size
mov es,di ;/ of target buffer.
lea di,[cs:gbRcvBuf] ;/
mov cx,size gbRcvBuf ;/

@@CBOnReceive9:
iret
; retf

;---------------

@@OnRcvDataReady:
mov [cs:gRcvSiz],cx ;Store # of bytes actually received
jmp @@CBOnReceive9

;---------------

@@OnRcvDiscard:
xor di,di ;Discard the packet
mov es,di ;/
xor cx,cx
inc [cs:gRcvMis]
jmp @@CBOnReceive9

;----------------------------
CBOnReceive endp
;----------------------------


[[[ Polling for a filled buffer

jmp @@SockUDPGetBlk3
;---------------
@@SockUDPGetBlk1:
mov [gRcvSiz],0000h ;Mark buffer as empty
@@SockUDPGetBlk2:
xor al,al
sub [@@wTimeout],1
jbe @@SockUDPGetBlk_E

xor cx,cx ;1 mili-seconds
mov dx,1000 ;/
mov ah,86h ;Delay
int 15h ;/

@@SockUDPGetBlk3:
cmp [gRcvSiz],0000h ;Anything received ?
jz @@SockUDPGetBlk2 ;Nope

if @@cDebug
call TTYStr,offset @@TXT_Header

call ShowRecETH,offset [gbRcvBuf].BLKUDP_ETH
endif
;---------------

cmp [gbRcvBuf].BLKREQ_ETH.ETH_Typ,TYP_ETH_ARP_HE ;ARP ?
jne @@SockUDPGetBlk4 ;Nope

call HandleARP

jmp @@SockUDPGetBlk2 ;Try again

;---------------

@@SockUDPGetBlk4:
etc.
Mateusz Viste
2019-10-12 12:03:58 UTC
Permalink
Post by R.Wieser
Post by Mateusz Viste
How come your router needs to send 4 ARP packets to you? It should
stop after the first one that you answer to.
It doesn't. It sends it to the broadcast IP, with a zero MAC. And
as such there is, I think, nothing I should be answering to (but do
correct me if I'm wrong here).
I really don't know why your router would send a frame with a zeroed
MAC. Can you perform a tcpdump capture of the actual traffic? This would
help to clear out what it is that this router actually does, without
relying on assumptions.
Post by R.Wieser
Post by Mateusz Viste
And why is the targeted machine only sending a single ARP
requests?
I can only guess to that I'm afraid. Maybe because it thinks the
router serves as a kind of server in this regard ?
Sounds quite esoteric to me. Again, I traffic dump would be helpful to
understand what's going on exactly.
Post by R.Wieser
That would also explain why the router is responding to a broadcast
to a port it shouldn't have open.
TCP/UDP stacks respond to requests on ports that are closed. TCP sends
back a TCP/RST segment, while UDP usually answers with an ICMP "port
unreachable" message. In both cases, the machine needs to resolve
the MAC of the peer first, through an ARP query.
Post by R.Wieser
Sure, if you don't mind looking at Assembly. Which parts do you want
to see ? And I hope you don't mind looking at a lot of experimental
code ... (some code added to the bottom)
I glanced through it, here are some thoughts:

You are returning from the callback routine with an IRET - why? This is
not an interrupt routine... The (commented out) retf would seem to be
the proper thing to do.

You are also overwriting CX with either 0 (when pkt rejected) or the
size of your buffer. I don't think you are supposed to do that, and I
wonder what kind of side effect it could lead to. CX is not for you to
fiddle with.

You are also trashing AH, which may or may not be a problem for the
packet driver. Simply said, your callback should not modify any
registers other than ES and DI.

The BIOS int 15h call for waiting might not do what you expect - while
it almost certainly will wait some 1ms or so, it might not do that in a
'power efficient' way. I did observe, at least on some BIOS
implementations, that this was implemented as a dumb busy loop.

Your code also gets stuck as soon as you receive a non-ARP frame, since
it jumps to SockUDPGetBlk2 without resetting gRcvSiz. You probably
meant to write "jmp @@SockUDPGetBlk1 ; Try again" instead.

HandleARP is not included, so I can't tell whether or not it is
resetting gRcvSiz properly.
Post by R.Wieser
But, as mentioned, I think the basic problem is that my polling (for
the buffer to be filled) is simply too slow.
This would mean that you consistently receive multiple packets at the
very exactly same time. It is possible, but I doubt that is is what
happens.
Post by R.Wieser
The whould "trouble" is that a system (the router) is responding to a
request not ment for it. Unplugging the hub (which connects the DOS
to the XP 'puter) from the router makes all of it go away.
A tcpdump traffic capture would tell us more. Is it *truly* a hub that
you use (as opposed to a switch)? If yes, then you could hook up some
extra Linux machine to it, and run:
tcpdump -ni eth0 -s0 -w capture.pcap

It would be interesting to look at capture.pcap then.

If it's a switch however, then the above won't work, as a switch is not
duplicating frames over all its ports. A wireshark dump from the XP
machine might tell us something, but best would be to place a
transparent bridge between the DOS PC and the switch, and do the
capture there.
Post by R.Wieser
Post by Mateusz Viste
I use single-packet buffers in both EtherDFS and ethflop, along
with some crude retransmission code. Works as expected (ie. well).
In other words, it wouldn't be a bad idea to take a peek at it. :-)
Well, you can take a look of course, but I did not want to imply that
my code is by any measure a good example or the "right" way of doing
things. It works for me, though.
Post by R.Wieser
Post by Mateusz Viste
executing an int 28h when no packet is found in the queue.
I could try that I suppose.
Until you have the true problem debugged, I'd rather recommend using a
stupid busy loop. You don't want adding new problems to the mix.
Post by R.Wieser
But ... now you've mentioned it (and I'm stuck anyway :-) ) the time
has come to try it. Looking in RBIL I see SS:SP mentioned as having
to(?) point to the "top of MS-DOS stack for I/O functions". Any
remarks to that, or can I just keep it inside my program ?
To be honest I never bothered with that (and did not have any
related troubles). If you're unsure, you could use the alternative
INT 2F/AX=1680h instead. But in any case, as said previously, I think
it would be best to stick to a simple busy loop for now. Once it works,
then you may think about ways of making it eco-friendly.

Mateusz
R.Wieser
2019-10-14 10:07:31 UTC
Permalink
Mateusz,
Post by Mateusz Viste
I really don't know why your router would send a frame with a
zeroed MAC.
... *and* a /broadcast/ IP.

After pondering about that for a while the answer seems to be, in
retrospect, rather obvious: Its asking /all/ 'puters in the lan to respond
(so it can update its ARP list).
Post by Mateusz Viste
In both cases, the machine needs to resolve
the MAC of the peer first, through an ARP query.
True, but why than is it using a scatter gun instead of a precisely aimed
nudge ? Also, if the source 'puter isn't part of the current LAN it won't
even get the needed response ...
Post by Mateusz Viste
Can you perform a tcpdump capture of the actual traffic?
Nope, sorry. I do not really want to install it on the (Windows) 'puter I'm
trying to communicate with, so I need to find another (with a
temporary/trashable OS), connect it to the LAN and hope it captures
everything.
Post by Mateusz Viste
You are returning from the callback routine with an IRET - why?
This is not an interrupt routine... The (commented out) retf would
seem to be the proper thing to do.
Take a wild guess to why I did that and commented the other one out. I dare
you ! :-)

To be honest, I tested both to try to figure out which one I /should/ be
using. I still do not know (it seems to works either way - which surprises
me). :-(

What do you use there and how did you know ? The packet driver specs do
not mention anything about it, and my searches did not turn up anything in
that regard either (if you have documentation in that regard I would be much
obliged).
Post by Mateusz Viste
You are also overwriting CX with either 0 (when pkt rejected)
...
Post by Mateusz Viste
CX is not for you to fiddle with.
How do you know ? The specs do not mention that. And no, I'm not going
for a "if not mentioned its not allowed" reasoning, as the reverse is also
true ("if its not forbidden its allowed").

But, if you ask: I took a lead from basic procedure calling, where just a
few registers must be the same on exit as they where on entry (unless
ofcourse, as is the case here, otherwise stated). AX, CX and DX are not
among them.
Post by Mateusz Viste
Simply said, your callback should not modify any
registers other than ES and DI.
As they say on wikipedia, "Citation needed" (no offense intended or
implied - just don't want to run on assumptions if I don't have to).
Post by Mateusz Viste
The BIOS int 15h call for waiting might not do what you expect -
while it almost certainly will wait some 1ms or so, it might not do
that in a 'power efficient' way.
That, especially at this moment, doesn't matter. Its a wait that will work
on every machine the program is run on, and that alone makes it preferrable
over any hack I can come up with myself ("in al,0x70" seems to take a fixed,
longish time).

But any suggestion to a better /generic/ way to do a wait there ?
Preferrably I would like to have a system-based wait on the "gRcvSiz" being
altered/changed from zero. Though that could ofcourse also suffer from the
not 'power efficient' problem ...
Post by Mateusz Viste
Your code also gets stuck as soon as you receive a non-ARP frame,
since it jumps to SockUDPGetBlk2 without resetting gRcvSiz.
...
Post by Mateusz Viste
HandleARP is not included, so I can't tell whether or not it is
resetting gRcvSiz properly.
The "HandleARP" function copies the (small) ARP request in its internal
buffer and sets "gRcvSiz" to zero - because I did not want to keep the
recieve buffer occupied for too long.
Post by Mateusz Viste
This would mean that you consistently receive multiple packets at
the very exactly same time. It is possible, but I doubt that is is what
happens.
I'm rather convinced that that is /exactly/ what happens - or at least close
enough. As you can see I have a counter that increments when I drop a
packet (because the buffer is already occupied), and that consistently shows
a One when I do not get a (visible) response from the targetted 'puter
(which is a bit odd in itself, as I would have expected higher counts,
especially when the targetted 'puter fires off its own (multiple) ARP
requests)
Post by Mateusz Viste
Post by R.Wieser
Post by Mateusz Viste
executing an int 28h when no packet is found in the queue.
I could try that I suppose.
Until you have the true problem debugged, I'd rather recommend using
a stupid busy loop. You don't want adding new problems to the mix.
:-) Thats my modus operandi too. But as I was already stuck it could not
hurt to /temporarily/ replace the "stupid wait" with it. Alas, it didn't
work for me (will probably have another look at it later).
Post by Mateusz Viste
Once it works, then you may think about ways of making it
eco-friendly.
Exactly. "Premature optimalisations" and all that :-( :-)

Regards,
Rudy Wieser
Mateusz Viste
2019-10-14 12:29:35 UTC
Permalink
Post by R.Wieser
Post by Mateusz Viste
I really don't know why your router would send a frame with a
zeroed MAC.
... *and* a /broadcast/ IP.
After pondering about that for a while the answer seems to be, in
retrospect, rather obvious: Its asking /all/ 'puters in the lan to
respond (so it can update its ARP list).
Sending a frame with a zeroed src MAC address is nothing obvious.
Unless you meant something else than I assumed when writing "it sends
the packet with a zero MAC".
Post by R.Wieser
Post by Mateusz Viste
In both cases, the machine needs to resolve
the MAC of the peer first, through an ARP query.
True, but why than is it using a scatter gun instead of a precisely
aimed nudge ?
At the time your router is doing the ARP discovery, it doesn't know
the MAC address of its peer. Learning it is the whole point of the
operation.
Post by R.Wieser
Also, if the source 'puter isn't part of the current
LAN it won't even get the needed response ...
That's what routing tables are for. If peer inside LAN then ARP
discovery, else ip route lookup.
Post by R.Wieser
Post by Mateusz Viste
You are returning from the callback routine with an IRET - why?
This is not an interrupt routine... The (commented out) retf would
seem to be the proper thing to do.
Take a wild guess to why I did that and commented the other one out.
I dare you ! :-)
Because you like to live dangerously? That's my only guess.

I looked into the source of a few packet drivers (pcntpk.asm,
3c509.asm, umac.asm). That's how they call the frame-receiving callback:

push cx
call recv_find
pop cx
Post by R.Wieser
What do you use there and how did you know ? The packet driver
specs do not mention anything about it, and my searches did not turn
up anything in that regard either (if you have documentation in that
regard I would be much obliged).
The code of Crynwr packet drivers is publicly available. Look at the
source.
Post by R.Wieser
Post by Mateusz Viste
You are also overwriting CX with either 0 (when pkt rejected)
...
Post by Mateusz Viste
CX is not for you to fiddle with.
How do you know ? The specs do not mention that. And no, I'm
not going for a "if not mentioned its not allowed" reasoning, as the
reverse is also true ("if its not forbidden its allowed").
That's called "defensive programming" in my book. But of course you are
free to assume that all packet drivers in the world are handling
gracefully the situation when a callback changes arbitrary register.
And *maybe* you will be right.

Now, specifically about CX: as shown in the code snippet I pasted
above, at least some of the Crynwr packet drivers won't be offended by
a CX change. Additionally, it appears that since the pktdrvr version
1.10, the application is indeed allowed to modify CX as to let the
driver know the exact size of the application's buffer. Is your packet
driver 1.10 compliant? You are supposed to check that with AH=10 (says
the pkt drvr spec 1.11).

Also, at the same time I found this mention in the latest spec, that
should definitely answer an earlier question you had:

"Note that many drivers are not re-entrant, and so are unable to process
functions (particularly send_pkt()) while either receiver() upcall is
in progress."
Post by R.Wieser
Post by Mateusz Viste
The BIOS int 15h call for waiting might not do what you expect -
while it almost certainly will wait some 1ms or so, it might not do
that in a 'power efficient' way.
That, especially at this moment, doesn't matter. Its a wait that
will work on every machine the program is run on, and that alone
makes it preferrable over any hack I can come up with myself ("in
al,0x70" seems to take a fixed, longish time).
But any suggestion to a better /generic/ way to do a wait there ?
Myself, I rely on the 18.2 hz BIOS timer at 0040:006C. The only catch
(that I am aware of) is that interrupts must be enabled for this to
work.
Post by R.Wieser
Post by Mateusz Viste
Your code also gets stuck as soon as you receive a non-ARP frame,
since it jumps to SockUDPGetBlk2 without resetting gRcvSiz.
...
Post by Mateusz Viste
HandleARP is not included, so I can't tell whether or not it is
resetting gRcvSiz properly.
The "HandleARP" function copies the (small) ARP request in its
internal buffer and sets "gRcvSiz" to zero - because I did not want
to keep the recieve buffer occupied for too long.
That's cool. But did you fix the bug I mentioned earlier?
Post by R.Wieser
Post by Mateusz Viste
This would mean that you consistently receive multiple packets at
the very exactly same time. It is possible, but I doubt that is is
what happens.
I'm rather convinced that that is /exactly/ what happens - or at
least close enough.
Without a traffic dump I am afraid we will only be able to
rely on convictions.

Mateusz
R.Wieser
2019-10-14 13:54:02 UTC
Permalink
Mateusz,
Post by Mateusz Viste
Unless you meant something else than I assumed when writing "it
sends the packet with a zero MAC".
My apologies, I should have been specific there: It sends a packet with a
zero /target/ MAC (and a broadcast target IP)
Post by Mateusz Viste
At the time your router is doing the ARP discovery, it doesn't
know the MAC address of its peer. Learning it is the whole point
of the operation.
Using a scatter gun ? That doesn't sound obvious to me /at all/.

If I want to know the adress of a certain person in a group /and I already
know his/her name/ I'm not going to shout into the whole group to deliver
their adresses, and than discard all but the one of the person I was after
(unless it was for a birthday surprise or something like that ofcourse :-) )
Post by Mateusz Viste
That's what routing tables are for.
On a /broadcast/ IP ? (and somehow I seem to remember that those are
blocked at the router, but I could be wrong there).
Post by Mateusz Viste
Because you like to live dangerously? That's my only guess.
Another possibility: I had/have no idea which one was/is asked for.
<whistle>
Post by Mateusz Viste
I looked into the source of a few packet drivers (pcntpk.asm,
3c509.asm, umac.asm). That's how they call the frame-receiving
push cx
call recv_find
pop cx
I already wrote a "thank you", but that can't be right: the packet-driver is
given a seg:offs vector to jump to, and that certainly aint looking like an
indirect jump ...
Post by Mateusz Viste
The code of Crynwr packet drivers is publicly available. Look
at the source.
Hmmm... That looks easier/faster than pulling the packet driver thru a
disassembler ofcourse (which I hadd already noted in my agenda). Either
that, or grabbing a few bytes from before the return addres and disassemble.
Post by Mateusz Viste
That's called "defensive programming" in my book.
Yep, thats a concept I'm also familiar with. I only allow it to stretch
for so far though (like if-and-when it blocks my experiments it goes outof
the window).
Post by Mateusz Viste
Now, specifically about CX: as shown in the code snippet I pasted
above, at least some of the Crynwr packet drivers won't be offended
by a CX change. Additionally, it appears that since the pktdrvr
version 1.10, the application is indeed allowed to modify CX as to let
the driver know the exact size of the application's buffer.
Ah, that explains why your code snippet throws CX away: Its from an old
packet-driver. I was already wondering.
Post by Mateusz Viste
Is your packet driver 1.10 compliant?
:-) How many ethernet cards do you (still) have that are not ? I hope
you do realize that the 1.11 spec is from two and a half decades ago.
Although I'm known for retaining "old crap" I don't think I've still got
'puters (and associated extension cards) /that/ old. :-)

But no, I'm currently not checking it. Current status of my program:
Getting the basics to work first. If that doesn't than all kinds of
"defensive programming" (needed!) bells-and-whistles are wasted time.

Nonetheless, thanks for mentioning that difference. Its something to
remember.
Post by Mateusz Viste
Also, at the same time I found this mention in the latest spec, that
"Note that many drivers are not re-entrant, and so are unable to process
functions (particularly send_pkt()) while either receiver() upcall is
in progress."
And thats probably why I forgot all about it: No mentioning about how to
check if the driver is or isn't re-entrant. :-(

And a heads up: Just above it the specs is mentioned "First, on the AX == 0
call, a non-zero value in DX is the length of the data in a 'look-ahead
buffer' pointed to by DS:SI.". I've found different results, with DL
containing the packet type (in my case 1 or 10), DH undefined and CX the
size of the full data.
Post by Mateusz Viste
Myself, I rely on the 18.2 hz BIOS timer at 0040:006C. The only
catch (that I am aware of) is that interrupts must be enabled for this
to work.
:-) I was trying to find out what a 'power efficient' wait loop (in DOS)
would look like.
Post by Mateusz Viste
That's cool. But did you fix the bug I mentioned earlier?
Nope. That was the code I started the thread with.
Post by Mateusz Viste
Post by R.Wieser
Post by Mateusz Viste
This would mean that you consistently receive multiple packets at
the very exactly same time. It is possible, but I doubt that is is
what happens.
I'm rather convinced that that is /exactly/ what happens - or at
least close enough.
Without a traffic dump I am afraid we will only be able to
rely on convictions.
As I already mentioned, I have a "dropped packet" counter, which most always
show a One when the connection fails.

So I hacked a single "overflow" buffer (to catch the first - and in this
case only - dropped packet). And it indeed shows either an ARP or an UDP
packet (both directed at my 'puters IP) coming from the targetted 'puter.
For me thats proof enough. Might still do some double-checking later on
though.

But, I'm curious: What do you think to be able to get from that traffic dump
that you think you cannot get otherwise ? Or do you simply not trust the
data I'm providing ?

Regards,
Rudy Wieser
R.Wieser
2019-10-14 16:35:35 UTC
Permalink
Mateusz ,
Post by Mateusz Viste
I looked into the source of a few packet drivers (pcntpk.asm,
push cx
call recv_find
pop cx
I just did the same. Below you can find two routines that do the "I have
data for you" callback. The first from a SIS900, the second for an RTL8029
card. Both show a PUSHF just before the far indirect call, which does
seem to indicate that the return should be an IRET.

The fact that both an RETF as well as an IRET work is me being lucky having
neither AX or BX altered (mind you, when using an IRET that does not matter.
Yes, the writers of those packet-drivers where also nodding to the
"defensive programming" principle. :-) ).

Regards,
Rudy Wieser

- - - - - - - - - - - - - - - - - - - - - - - -
-- SIS900

0001007F sub_0_7F:
0001007F 55 push bp
00010080 8B EC mov bp, sp
00010082 06 push es
00010083 53 push bx
00010084 56 push si
00010085 57 push di
00010086 1E push ds
00010087 8B 5E 08 mov bx, [bp+8]
0001008A 8B 4E 0A mov cx, [bp+0Ah]
0001008D B8 00 00 mov ax, 0
00010090 F9 stc
00010091 50 push ax
00010092 9C pushf
00010093 FF 5E 04 call dword ptr [bp+4]
00010096 58 pop ax
00010097 83 F8 00 cmp ax, 0
0001009A 74 01 jz loc_0_9D
0001009C 58 pop ax
0001009D loc_0_9D:
0001009D 1F pop ds
0001009E 8B C7 mov ax, di
000100A0 8C C2 mov dx, es
000100A2 5F pop di
000100A3 5E pop si
000100A4 5B pop bx
000100A5 07 pop es
000100A6 5D pop bp
000100A7 C3 retn

- - - - - - - - - - - - - - - - - - - - - - - -
-- RTL8029

00010AB2 loc_0_AB2:
00010AB2 B8 00 00 mov ax, 0
00010AB5 F9 stc
00010AB6 50 push ax
00010AB7 9C pushf
00010AB8 FF 1E 98 03 call dword ptr word_0_398
00010ABC 5B pop bx
00010ABD 83 FB 00 cmp bx, 0
00010AC0 74 03 jz locret_0_AC5
00010AC2 83 C4 02 add sp, 2
00010AC5 locret_0_AC5:
00010AC5 C3 retn

- - - - - - - - - - - - - - - - - - - - - - - -
R.Wieser
2019-10-14 17:00:30 UTC
Permalink
Mateusz,

[Quote myself]
The fact that both an RETF as well as an IRET work is me being lucky having
neither AX or BX altered (mind you, when using an IRET that does not matter.
[/Quote]

I was wondering about the "cmp ax" / "cmp bx", "jnz xxx" following the far
indirect call (it looks rather odd). But than the quarter dropped: when you
use an IRET the POP following the far indirect call it will return the
origional AX (which is zero) and skip the "pop" / "add sp,2" following the
"jz", but when you use a RETF the POP will return the pushed flags, and
/not/ be zero, and thus remove the origional-pushed AX.

In short: It doesn't matter which one of the two (IRET or RETF) you use.
Smart guys those programmers. :-)

Regards,
Rudy Wieser
Mateusz Viste
2019-10-14 17:12:22 UTC
Permalink
Post by R.Wieser
I just did the same. Below you can find two routines that do the "I
have data for you" callback. The first from a SIS900, the second for
an RTL8029 card. Both show a PUSHF just before the far indirect
call, which does seem to indicate that the return should be an IRET.
I do not think it does. See below.
Post by R.Wieser
The fact that both an RETF as well as an IRET work is me being lucky
having neither AX or BX altered (mind you, when using an IRET that
does not matter.
I took another look after your previous reply, because I started
doubting. And I saw that the 'recv_find' routine is not a reference
to the callback, as I initially assumed. It is a routine that is hidden
in another source file shared by all crynwr drivers ("head.asm"). Its
content is rather interesting:

mov ax,0 ; allocate request.
stc ; with stc, flags must be an odd number
push ax ; save a number that cant be flags
pushf ; save flags in case iret used.
call receive_ptr ; ask the client for a buffer.
; on return, flags should be at top of stack. if IRET has been used,
; then 0 will be at the top of the stack
pop bx
cmp bx,0
je recv_find_4 ; 0 is at top of stack
add sp,2
recv_find_4:
ret

With this clever code Russ covered both cases - that's why retf and
iret both work. Now, that does not answer precisely what would the
"correct" way be. I still think a retf makes more sense, but I admit
this may be debatable matter.
Post by R.Wieser
Yes, the writers of those packet-drivers where also
nodding to the "defensive programming" principle. :-)
They were, definitely. Question remains - did all packet driver authors
tolerate both iret and retf? And if not - which one did they expect?
Post by R.Wieser
How many ethernet cards do you (still) have that are not ? I hope you
do realize that the 1.11 spec is from two and a half decades ago.
Although I'm known for retaining "old crap" I don't think I've still
got 'puters (and associated extension cards) /that/ old. :-)
Well, this thread is about programming with a DOS packet driver on a
computer that is supposedly too slow to handle two ARP queries at
once... so I assume we are not talking latest hi-tech hardware. :-)

I looked on my own PCs, they all run v1.09 packet drivers. I probably
used whatever I found first and never cared to update.
Post by R.Wieser
But, I'm curious: What do you think to be able to get from that
traffic dump that you think you cannot get otherwise ? Or do you
simply not trust the data I'm providing ?
A traffic dump shows what happens on the wire, without the need to rely
on assumptions or interpretations. While I trust you do diligent
debugging, it would still be nice to see actual packets black on white.
The added benefit of a traffic dump is that it contains timestamps -
this would allow to observe how far apart the ARP answers truly are,
possibly translating this value to a number of CPU cycles so we'd know
whether or not it is "normal" for your machine to really miss an ARP.
Finally, I still doubt that your XP machine fails after a single ARP
attempt. And if it repeats its ARP query (as it should), then the "I
get two ARPs at the very same time" scenario becomes much less likely.


Mateusz
R.Wieser
2019-10-14 19:06:32 UTC
Permalink
Mateusz,
Post by R.Wieser
which does seem to indicate that the return should be an IRET.
I do not think it does. See below.
Agreed, as my follow-up ("blimy!") shows.
Post by R.Wieser
I still think a retf makes more sense, but I admit
this may be debatable matter.
Personally I think an iret makes more sense, 'cause that bit of code
interrupts whatever my code was doing at the time (even if just running a
polling loop waiting for a new buffer). But, with smart code like that,
who cares. Its definitily not something I want to rant about / start a
flamewar over. :-)
Post by R.Wieser
They were, definitely. Question remains - did all packet driver authors
tolerate both iret and retf? And if not - which one did they expect?
Thats a good question. If you find any documentation which describes when
(as in PDS version) the switch from accepting only one of those (doesn't
matter which) to the trick code we now have found than I would like to have
an heads-up too. If only to be able to check for a minimally needed
version for my code to run on.
Post by R.Wieser
Well, this thread is about programming with a DOS packet driver
on a computer that is supposedly too slow to handle two ARP
queries at once...
Assumptions, assumptions. Maybe its not the 'puter which is the problem,
but just my code that simply does too much between being able to receive
packets.
Post by R.Wieser
so I assume we are not talking latest hi-tech hardware. :-)
True. The DOS 'puter runs on 100 MHz, with a 10 MBit connection (don't
ask). Thats not really fast. Especially not when the other two (switch
and XP) have gigabit capabilities ("high speed" in comparision).
Post by R.Wieser
I looked on my own PCs, they all run v1.09 packet drivers. I
probably used whatever I found first and never cared to update.
How did you do that ? All my network cards need(?) packet driver solutions
tailored to the specific hardware. And as those have been mostly bought
within this century ...

Regards,
Rudy Wieser
Mateusz Viste
2019-10-14 20:44:17 UTC
Permalink
Post by R.Wieser
Agreed, as my follow-up ("blimy!") shows.
Yes, seems we did the same research - albeit I was looking at the
source code (clumsily the first time, I must say), while you were (I
think?) looking at disassembly listings.
Post by R.Wieser
Personally I think an iret makes more sense, 'cause that bit of code
interrupts whatever my code was doing at the time (even if just
running a polling loop waiting for a new buffer). But, with smart
code like that, who cares. Its definitily not something I want to
rant about / start a flamewar over. :-)
On 04.08.1992, one Felix Huber posted a packet driver code to
comp.sys.novell. There, I read:

add cx,14 ;add header_len
push cx
mov ax,0
call dword ptr cs:[peer_list.hdl_off] ;call them
pop cx
mov ax,es
or ax,di ;interested in packet?
jne new_handler_copy
linc packets_dropped
retf ;they don't want it
new_handler_copy:

Your code wouldn't work with his. Not that it would matter much, I
guess - it is simply the only "non-crynwr" packet driver code I was able
to find with a quick web search.
Post by R.Wieser
Thats a good question. If you find any documentation which
describes when (as in PDS version) the switch from accepting only one
of those (doesn't matter which) to the trick code we now have found
than I would like to have an heads-up too.
I don't think an answer exists. As you know, the PDS is not explicitly
telling whether the receiver should return with an iret or a retf, so
it all boils down to 'common usage'. And finding significant historical
samples would require some serious archaeology.
Post by R.Wieser
True. The DOS 'puter runs on 100 MHz, with a 10 MBit connection
(don't ask). Thats not really fast. Especially not when the other
two (switch and XP) have gigabit capabilities ("high speed" in
comparision).
100 MHz is what I'd call a very fast PC. A couple years ago I was
playing with a simple ARP/IP/UDP stack on my 80286 and it wasn't
loosing frames so easily.
Post by R.Wieser
Post by Mateusz Viste
I looked on my own PCs, they all run v1.09 packet drivers. I
probably used whatever I found first and never cared to update.
How did you do that ? All my network cards need(?) packet driver
solutions tailored to the specific hardware. And as those have been
mostly bought within this century ...
My NICs are mostly 3C509 and similar, dating from 1992-1993.

But your hardware is also not guaranteed to be using a 1.11-compliant
packet driver. You say it comes with a 10 Mbps card (unless "10 Mbps
connectivity" means something else), so chances are it is pre-1995,
since FastEthernet became available only in 1995. That would be
consistent ("period-correct") with the 100 MHz CPU that you mention:
the DX4 was released in March 1994.
The PDS v1.11, on the other hand, has been published in June 1994. All
very close.

Back to the initial subject - have you tried implementing a ring buffer
in your program? Does it solve the problem? Genuinely curious.

Mateusz
R.Wieser
2019-10-15 07:07:36 UTC
Permalink
Mateusz,
while you were (I think?) looking at disassembly listings.
Yep. IDA freeware.
On 04.08.1992, one Felix Huber posted a packet driver code
[snip code]
Your code wouldn't work with his.
"Your /current/ code wouldn't work with his" - there is a reason I kept the
"retf" remarked there. :-)

I "greatly dislike" (to evade the word "hate") situations like this. Even
with the (PDS) documentation in my hands not actually knowing what is
expected from me when I want to use the API. And that includes not having
the foggiest how, in this case, to test if a certain PD adheres to a certain
PDS version :-(
100 MHz is what I'd call a very fast PC. A couple years ago I
was playing with a simple ARP/IP/UDP stack on my 80286 and
it wasn't loosing frames so easily.
Its probably a bad combination of factors. Like my switch butting in when
it shouldn't. Long ago I wrote some code that allowed me to access a
"harddisk" on a DOS machine that used UDP to get its actual data from a
(thanwhile) W98 machine. It worked well, even with the "just a single
buffer" method.
But your hardware is also not guaranteed to be using a 1.11-compliant
packet driver. You say it comes with a 10 Mbps card (unless "10 Mbps
connectivity" means something else)
It does. Its the hub I'm using which is the culprit in that (that was the
"don't ask" part :-) ). The SIS900 driver just detects the available speed
and reports it.
Back to the initial subject - have you tried implementing a ring
buffer in your program? Does it solve the problem? Genuinely
curious.
Not yet. It will need a large code overhaul, as the current code uses
fixed adresses for the ethernet buffer. But will it solve the problem ?
Yep, most likely. It ofcourse fully depends on how busy the LAN is, and
how many buffers I allow the program to generate/have.



Though I have a bit of a "problem" (of sorts) with the ring buffer itself.
The basic "is the buffer empty" (tail = head) and "is the buffer full"
(head+1 = tail) checks have a drawback: the buffer is considered to be full
even when there is an empty buffer available (the one "head" points at has
been worked at and emptied). Which is rather wastefull when you just have
a few (like four) buffers available.

So, I'm currently trying to think of a method which will allow me to have
/all/ buffers occupied - without sacrificing the robustness of the above
simple tests.

Regards,
Rudy Wieser
Mateusz Viste
2019-10-15 08:42:48 UTC
Permalink
Even with the (PDS) documentation in my hands not actually knowing
what is expected from me when I want to use the API.
If you're motivated enough, you could follow Russ' lead and perform some
crazy shenanigans to detect what the pktdrvr expects:
- look at the stack
- if word in stack == flags, then IRET

That's not 100% bulletproof, since the caller address might by chance
match the flags bit pattern, but it could still be better than
counting on luck. And with some minimal effort (that I did not
invest here), one could probably work out something more resilient.
Long ago I wrote some code that allowed me to access a "harddisk" on
a DOS machine that used UDP to get its actual data from a (thanwhile)
W98 machine. It worked well, even with the "just a single buffer"
method.
Sounds cool - and very similar to what I did with EtherDFS.
Not yet. It will need a large code overhaul, as the current code
uses fixed adresses for the ethernet buffer. But will it solve the
problem ? Yep, most likely. It ofcourse fully depends on how busy
the LAN is, and how many buffers I allow the program to generate/have.
The NIC is supposed to have multiple hardware buffers on its own - esp.
a modern card like the SIS900. Seems that part of the problem could be
that the packet driver is trying to deliver frames immediately as they
arrive, and drops them if receiver's not ready. I wonder if there is
any way to make the card use its buffers for actual buffering so the
pktdrvr could retry a frame delivery after a short time, or try
delivery only if told it's okay to. Perhaps performing a cli as soon as
you see the "packetbuff busy" flag would help? (and then doing an sti
only once you processed it and freed buff)
Though I have a bit of a "problem" (of sorts) with the ring buffer
itself. The basic "is the buffer empty" (tail = head) and "is the
buffer full" (head+1 = tail) checks have a drawback: the buffer is
considered to be full even when there is an empty buffer available
(the one "head" points at has been worked at and emptied). Which
is rather wastefull when you just have a few (like four) buffers
available.
Maybe an easier option would be to use some stupid counter? Just a
thought, might be dumb.

unsigned char ring[4][1500];
unsigned short ringhead = 0;
unsigned short ringlen = 0;

/* receiver (callback) */
if (pktdrvr_wants_deliver_pkt) {
if (ringlen == 4) goto dropit;
write_pkt_to(&(ring[(ringhead + ringlen) & 3]));
ringlen++;
}

/* check for available packets */
while (ringlen) {
process_pkt(&(ring[ringhead]));
disable(); /* cli */
ringlen--;
ringhead++;
enable(); /* sti */
}


Mateusz
R.Wieser
2019-10-15 09:20:39 UTC
Permalink
Mateusz,
Post by Mateusz Viste
If you're motivated enough, you could follow Russ' lead and perform
Nope, zero motivation. That would be like trying to "opt out" of old
drivers, most of which I will not even know they exist. Thats not going to
end well. Rather, I expected an "opt in" - the packet driver tells me
which PDS they support, and mention that method in their documentation.
Ofcourse, it just /might/ already been done by the "PKT DRVR" signature in
the driver itself ...
Post by Mateusz Viste
Sounds cool - and very similar to what I did with EtherDFS.
Yep. It was fun to figure out the IFS on the DOS side, as well as what to
do with incomplete actions (like DOS never terminating a filesearch) on the
Windows side.
Post by Mateusz Viste
I wonder if there is any way to make the card use its buffers for
actual buffering so the pktdrvr could retry a frame delivery after
a short time, or try delivery only if told it's okay to.
Better yet: a method to tell them /not/ to push the buffer, but wait for me
to pull it. Alas, I have not seen the PDS v1.11 mention anything of the
kind. Than again, I don't think that many cards, especially older ones,
have such multiple buffers.
Post by Mateusz Viste
Maybe an easier option would be to use some stupid counter? Just
a thought, might be dumb.
It sounds like something to at least to consider. But I would need to be
extra careful, knowing that that counter is, effectivily, accessed by two
seperate threads (in other words, the increment and decrement need to be
atomic).

Regards,
Rudy Wieser
R.Wieser
2019-10-20 17:07:36 UTC
Permalink
Mateusz,
Post by Mateusz Viste
Maybe an easier option would be to use some stupid counter?
I just stumbled over the below page. I'm mulling over it.

https://www.snellman.net/blog/archive/2016-12-13-ring-buffers/

Regards,
Rudy Wieser
src153
2019-10-20 18:25:01 UTC
Permalink
Post by R.Wieser
I just stumbled over the below page. I'm mulling over it.
https://www.snellman.net/blog/archive/2016-12-13-ring-buffers/
His "Array + two unmasked indices" scheme has caveats, as he admits.
No it doesn't.
Post by R.Wieser
empty() { return read == write; }
full() { return size() == array.capacity }
size() { return write - read; }
full() also calls size(). That's not simpler.

Avoiding 1 wasted slot is not worthwhile.

But even he agrees: Head is where you read from the buffer. Tail is
where you write to the buffer. Head = oldest, tail = newest.

Same terminology as a linked list. Head points to the first (oldest)
item in the list. Tail points to the last (newest).

Who's at the head of a line? Whoever got there first.

https://howdoesinternetwork.com/2015/hol-head-of-line-blocking

Rod Pemberton
2019-10-11 18:24:16 UTC
Permalink
On Fri, 11 Oct 2019 15:32:27 +0200
Post by R.Wieser
I'm trying to communicate from a DOS 5 machine with one running
Windows, using a packet driver. To find my target 'puter I do an
UDP broadcast for a certain port.
The problem is that both my router as well as the targetted 'puter
respond with ARP request messages, and that my DOS 'puter is simply
too slow to be able to discard the routers ARP message (which is send
to the broadcast IP), and as a result drops the ARP message from the
targetted 'puter. Hence the connection fails
I already got the idea to create multiple ARP request buffers, but
than realized that that would just push the problem a bit further
away - if multiple 'puters respond I could easily run outof ARP
buffers ...
I'm sure that this problem has been solved before, but my google-fu
isn't strong enough to find it. In other words: Does anyone have an
idea how this problem is normally handled ?
Too fast? I don't understand how that could be. I transferred files
from a C64 to a PC (IBM clone). Of course, that was over RS-232C, which
has flow-control lines controllable by both hardware (null modem) and
software.

Since you're using (ancient?) packet drivers, how old is the Ethernet
card? Any possibility that this could be an issue? I.e., newer faster
card might not have buffering issues?

Also, how slow can you set your router's speed? 100Mb? 10Mb? Maybe,
like my router, your router is forced to 100Mb only? or 1Gb only? Try
setting it to allow 10Mb or 10Mb/100Mb etc.

Any possibility an Ethernet crossover cable would help? E.g., direct
computer-to-computer, not through the router. I.e., you might be able
to communicate at lower speeds without the router in the middle.

Maybe, you need a serial (RS-232C) to Ethernet server? These devices
allow old RS-232C serial connections to connect to Ethernet. They
would probably support hardware packet buffering and flow-control.


Rod Pemberton
--
The U.S. government can't allow a government employee to anonymously
attack the President of the U.S.
Loading...