Re: [lwip-users] Zero window and refused data problem

2016-11-08 Thread Valery Ushakov
On Tue, Nov 08, 2016 at 09:53:52 +0100, Simon Goldschmidt wrote:

> 2) after storing a segment in "refused_data", no more ACKs are sent
> 
> The whole purpose of "refused_data" was to let the stack behave like
> a buffer overflowed: if your device cannot handle incoming data in
> the speed it is sent by the remote host, the remote host should
> throttle its sender. This is achieved by not handling/not answering
> a packet at all, just like it was dropped due to congestion. This
> should bring the remote host's TCP to send less. ACKing an old seqno
> instead might work for you, but I don't know what will be the result
> for all remote stacks, so I'm very reluctant to change this...
> 
> As you can see from this, TCP is meant to achieve the highest
> possible throughput possible for the combination of remote host,
> network and local host. What you want instead to make it a queue
> that keeps up a connection as long as possible without data being
> exchanged. I'm not fully convinced one can coexist with the other,
> but please come up with suggestions of how to fix this ;-)

I don't want to argue this for the general case but for the specific
zero window case this argument doesn't apply, I think, and quite
obviously (IMHO) so.

A PCB with zero window *explicitely* tells the peer to stop sending by
specifying zero window, so you don't have to pretend incoming packets
were lost and hope that the remote stack will correctly *infer* it
needs to throttle.  You just *tell* it to.

RFC1122 uses a printer out of paper as an example for zero window
state, something that can take ages (relatively speaking) to resolve
since it requires user intervention.  Stopping sending ACKs in this
case is problematic, since it causes connection to be aborted
relatively quickly.

RFCs actually do want zero window state to be able to "keep up a
connection as long as possible without data being exchanged".

E.g. RFC1122 says

 A TCP MAY keep its offered receive window closed indefinitely.
 As long as the receiving TCP continues to send acknowledgments in
 response to the probe segments, the sending TCP MUST allow the
 connection to stay open.

(There's RFC6429 that talks about potential for using that as a DoS
attack on the sender, but that's not what we are concerned about
here).

I think there are two options when the zero window probe may be
accepted because a tiny window has opened, but the window is still
small enough to advertise b/c we are avoiding silly window syndrome.

One course of action would be to ignore the probe.  It is most likely
partial data anyway, a byte borrowed from the next full batch that
will be sent when the window opens enough to advertise it.

Alternatively we can accept the probe as refused data, but then we
should relax the logic that decides to not send any ACKs when refused
data is present and do send the ACK if it also announces zero window.
In this case we can expect the next probe soon, that we will have to
reject and keep acking the first one.

The first option probably makes more sense in general as it will not
bother the app with that single probe byte that the app likely can't
process in isolation anyway.

But thinking a bit more about it - the refused data might have been
the last packet that completely filled the window and in this state we
want to send those acks with zero window when we have refused data
that was not a probe.

So i guess both bits of logic need to be implemented - refusing probes
if we can't advertise non-zero windows and keep sending the old ack,
and sending acks when refused data is present if the window is zero.

I don't think we should worry about the reaction of "all remote
stacks" to this as anything is better than actively causing the
connection to get aborted by not responding.

It might be argued indeed that the application shouldn't be "misusing
TCP as a queue", but I don't think punishing it with aborted
connections is proportional punishment.  If remote stacks will exhibit
suboptimal behaviour - *shrug* the app really shouldn't be misusing
TCP as a queue :), but at least lwip made its best effort (e.g. you
don't expect a kernel panic when you remove a file that doesn't
exist).

-uwe

___
lwip-users mailing list
lwip-users@nongnu.org
https://lists.nongnu.org/mailman/listinfo/lwip-users


Re: [lwip-users] Raw lwIP server write issue

2015-11-07 Thread Valery Ushakov
Amit Ashara  wrote:

> Do you mean that instead of using pcb I should have another tcp_pcb e,g,
> newpcb that is assigned from the pcb in the call back.
> 
> struct tcp_pcb *newpcb;
> 
> static err_t echo_accept(void *arg, struct tcp_pcb *pcb, err_t err)
> 
> {
>   LWIP_UNUSED_ARG(arg);
>   LWIP_UNUSED_ARG(err);
> 
>   newpcb = pcb;

Exactly.


> On Thu, Nov 5, 2015 at 11:28 AM, Valery Ushakov  wrote:
> 
>> Amit Ashara  wrote:
>>
>> > When a connection is established between the server and the client,
>> > I can use the tcp_write on the client side to send data in my
>> > application code.  However the same on the server side is not
>> > possible.  The pcb that has been used for the server only contains
>> > the server's address and server's port but not the client's address
>> > and client's port.  In the receive call back on the server side, I
>> > can send the data to the client but not outside of the call back.
>>
>> You are using wrong pcb.  On the server you start with a listening
>> pcb.  When your accept callback is called, it's passed a *new* pcb,
>> that represents the established connection.  You should use that pcb
>> for tcp_write.  Writing from receive callback works because in the
>> receive callback the pcb argument is that connection pcb, not the
>> original listening pcb.
>>
>> -uwe

-uwe


___
lwip-users mailing list
lwip-users@nongnu.org
https://lists.nongnu.org/mailman/listinfo/lwip-users


Re: [lwip-users] Raw lwIP server write issue

2015-11-05 Thread Valery Ushakov
Amit Ashara  wrote:

> When a connection is established between the server and the client,
> I can use the tcp_write on the client side to send data in my
> application code.  However the same on the server side is not
> possible.  The pcb that has been used for the server only contains
> the server's address and server's port but not the client's address
> and client's port.  In the receive call back on the server side, I
> can send the data to the client but not outside of the call back.

You are using wrong pcb.  On the server you start with a listening
pcb.  When your accept callback is called, it's passed a *new* pcb,
that represents the established connection.  You should use that pcb
for tcp_write.  Writing from receive callback works because in the
receive callback the pcb argument is that connection pcb, not the
original listening pcb.

-uwe


___
lwip-users mailing list
lwip-users@nongnu.org
https://lists.nongnu.org/mailman/listinfo/lwip-users


Re: [lwip-users] wrong checksum on some ICMP echo replies

2015-06-13 Thread Valery Ushakov
Fabian Koch  wrote:

> I opened an issue on my github fork of LWIP and fixed it there:
> https://github.com/tabascoeye/lwip/issues/17
> https://github.com/tabascoeye/lwip/commit/32c32d8e2681e1f456ad487ac9f4159f7e765d57
> 
> do you guys agree on this fix?

Looks correct.

-uwe


___
lwip-users mailing list
lwip-users@nongnu.org
https://lists.nongnu.org/mailman/listinfo/lwip-users


Re: [lwip-users] Virtual machines in the same host (bridge).

2015-02-07 Thread Valery Ushakov
Sylvain Rochet wrote:

> On Fri, Feb 06, 2015 at 01:29:28PM -0200, Norberto R. de Goes Jr. wrote:
>
>> I think the problem is in the my virtual environment (vm?s). I run the
>> application in real servers and the ping replies have success.
>> Thank you very much.
> 
> Yes, this is exactly what I previously said, the problem is (probably) 
> because your VM host bridge does not accept learning of foreign MAC 
> address.

"Internal Network" is not a VM/host bridge, just a piece of virtual
ethernet.

As the first mail of the thread said:

| But I did not get success still.  The pings from VM#2 go from the
| ethernet to the "br0"(VM#1) device and after to the "tap0" device.
| There the lwIP generates an answer and sends it to the asking
| host. But then the packages disappear.  They do not go back to the
| "br0" device (seen with dcpdump).

So the pongs seems to be lost between tap0 and br0 inside VM1.

BTW, VBox "NAT Network" is basically the same "Internal Network" with
an extra proxy process connected to it and that proxy happens to be
lwip-based :)

The notes I refered to in my previous mail are from the initial
prototype of it that I hacked together using unixsim with tap bridged
to VM's internal network connection, i.e. the setup that is used by
Norberto, as far as I understand.

-uwe


___
lwip-users mailing list
lwip-users@nongnu.org
https://lists.nongnu.org/mailman/listinfo/lwip-users


Re: [lwip-users] Virtual machines in the same host (bridge).

2015-02-03 Thread Valery Ushakov
Norberto R. de Goes Jr. wrote:

> - host Windows-7 Professional, 64 bits, with two virtual machines (Virtual
> Box), both  with Fedora-17 Distro, 32 bits;
> - the VM?s network configured as "Internal Network"
> 
> I wrote a small "lwip application" based on unix port
> (community). It runs in VM #1 and a "tap0" device is created with
> success. In the VM#2 no application is running.
[...]
> Please, are there any restriction in use the lwip library in virtual
> machines hosted on the same server? More specifically with linux
> bridge use?

This should work.  I used to have a similar setup, but I no longer
have it handy.  The following is based on my notes:

The VM where lwip ran did

  brctl addbr bridge0
  brctl addif bridge0 eth1

  ifconfig bridge0 up

once to init things.

Then tapif.c had changed

  #define IFCONFIG_ARGS "tap0 up # %d.%d.%d.%d"

and additional

  status = system("brctl addif bridge0 tap0");

at the end of low_level_init() since tap0 is removed from the bridge
when closed and needs to be added back when tapif.c opens it anew.

Note that neither bridge, nor tap has ip addresses configured.

-uwe


___
lwip-users mailing list
lwip-users@nongnu.org
https://lists.nongnu.org/mailman/listinfo/lwip-users


Re: [lwip-users] How to control TCP sending by raw API?

2014-09-10 Thread Valery Ushakov
Gavin  wrote:

> I make the below test code to verify TCP sending, it works, but something is
> unexpected.
> 
> const char *helloworld = "hello world\n";
> const char *helloworld1 = "hello world1\n";
> 
> err_t LAN_sent(void *arg, struct tcp_pcb *pcb, u16_t len)
> {
>tcp_write(pcb, helloworld, 12, 0);
>return ERR_OK;
> }
> 
> err_t LAN_sent1(void *arg, struct tcp_pcb *pcb, u16_t len)
> {
>tcp_write(g_pcb, helloworld1, 13, 0);
>return ERR_OK;
> }
> 
> int main()
> {
> ...
>if ((g_pcb = tcp_new()) == NULL)
>{
>mem_free(state);
>return ERR_MEM;
>}
> 
>tcp_arg(g_pcb, state);
>tcp_err(g_pcb, LAN_err);
>tcp_recv(g_pcb, LAN_recv);
>tcp_sent(g_pcb, NULL);
> 
>err = tcp_connect(g_pcb, &ipaddr, SERVER_PORT, LAN_sent);
>if (err != ERR_OK)
>{
>mem_free(state);
>tcp_abort(g_pcb);
>}
> 
>tcp_sent(g_pcb, LAN_sent1);
> ...
> }
> 
> And I get the such result on the server;
> 
> hello world
> hello world1
> hello world1
> hello world1
> hello world1
> ...
> 
> I expect that "hello world1" is just printed once like "hello world".

tcp_sent() is your ACK-callback, so to say.  When you send something,
remote acks its reception to you, so your tcp_sent callback is called,
which sends something, which remote acks, ... etc, etc.

So what you see is expected, given your setup.

-uwe


___
lwip-users mailing list
lwip-users@nongnu.org
https://lists.nongnu.org/mailman/listinfo/lwip-users


Re: [lwip-users] Closing TCP connections

2014-08-04 Thread Valery Ushakov
On Sun, Aug 03, 2014 at 16:21:07 +0400, Mark Lvov wrote:

> This is exactly what I've done, only I have a class, each instance of which
> manages a connection to a particular endpoint (only, my "state" enum has
> ACTIVE_CLOSE and PASSIVE_CLOSE instead of CLOSING, since those are handled
> differently). The thing is, it does not really help much with the problem
> I've outlined in the earlier message. Even though I get the pointer to a
> particular instance of the class in the "arg" argument to the err callback,
> it is still impossible to know if it is the latest connection, that errored
> out, or if it is some other, older connection, that was also opened to the
> same endpoint, but was stuck in some "waiting" state, such as LAST_ACK. I
> hope, this makes sense.

You seem to use "connection" here in a more abstract sense of
"association" between two entities that is served by an underlying TCP
connection (in the narrow sense), and that TCP connection may be
closed and reopened - as you described in an earlier email.

What you seem to be saying is that you associate an object
representing this high-level notion of connection with the tcp_pcb of
the underlying connection.

What Massimo is saying is that you need a separate object to represent
TCP connection that you can discard on error.

Either way, since TCP state machine and associated lwip callbacks are
known, you can track pcb state and know when to dissociate from it
(callbacks and arg), so you will always know your error callback
is called for the "current" pcb.

> On Sun, Aug 3, 2014 at 12:25 AM, M. Manca wrote:
> 
> >  Il 02/08/2014 20:52, Mark Lvov ha scritto:
> >
> > Hello,
> >
> > It seems, I still have some unanswered questions with regard to
> > correct connection teardown. Let's consider the active close situation
> > (we are closing the connection). We've just called tcp_closed and are
> > waiting for the tcp_recv callback to be called with an empty pbuf.
> > But, as I understand, if the remote side sends RST or does not send
> > anything at all, the err handler will be called instead. The problem
> > is, one does now know which particular connection (pcb) the callback
> > is addressed to, because the callback function does not receive a pcb
> > as an argument.
> >
> >  This is one of the reason I wrote an "upper layer" to the raw functions
> > to manage a tcp client connection.
> > The idea is simple: create a struct to embed every information needed to
> > manage a particular connection so I can pass it as the void *arg
> > that is also present in the error callback.
> > I think you can understand my idea just reading the struct I made:
> >
> > typedef enum
> > {
> >   STATE_NOT_CONNECTED = 0,
> >   STATE_CONNECTING,
> >   STATE_CONNECTED,
> >   STATE_CLOSING,
> > } TTcpRawSktState_e;
> >
> > typedef struct
> > {
> >TTcpRawSktState_e eState;
> >err_t eError;
> >struct pbuf *pPbuf;
> >struct tcp_pcb *pPcb;
> >struct ip_addr tServerIpAddr;
> >uint16_t wServerPort;
> >uint16_t wBindPort;
> >char szDescription[8];
> > } TTcpRawSkt;
> >
> > the description field isn't necessary, I used it to debug in the simplest
> > way my code.
> >
> >
> > Consider the scenario, when one needs to keep a connection open by
> > reconnecting to the remote side whenever the connection is closed
> > (either by the remote or the local side). It is all fine when the
> > remote side closes the connection - we just receive a NULL pbuf, after
> > that we can just call tcp_close on the "current" pcb, then immediately
> > ask for the new pcb and reconnect. If, on the other hand, *we* want to
> > close the connection (to reopen if afterwards), and call tcp_close, we
> > might have the err callback called and then we won't really know if it
> > means, that the current connection was terminated or some older
> > connection, that maybe stuck in LAST_ACK finally timed out.
> >
> > Does this mean, that in such a situation, one has to keep only one err
> > callback active at a time? It seems, the best course of action is to
> > zero out the err callback on a pcb after calling on it tcp_close
> > successfully (actually, its more like this: zero out the callback,
> > then call tcp_close and if it fails reattach the callback, because we
> > will have to wait a bit before calling tcp_close again). But then,
> > once we call tcp_close, we have to start a timer (for, say, 5
> > seconds?) and if it runs out we consider the connection closed, remove
> > all callbacks from that pcb and ask for the new one.
> >
> > Hopefully, I've managed to explain the problem I am facing. Sorry,
> > that it took such a long message.
> >
> > Thanks,
> > Mark
> >
> > On Fri, Aug 1, 2014 at 9:01 AM, Mark Lvov 
> >   
> > wrote:
> >
> >  Well, shame on me!
> >
> > I was actually 
> > usinghttp://git.savannah.gnu.org/cgit/lwip.git/tree/doc/rawapi.txt?id=5b8b5d459e7dd890724515bbfad86c705234f9ec
> > as a reference and it obviously lacks the details, that are present on
> > the 

Re: [lwip-users] TCP Checksum = 0xFFFF

2014-05-14 Thread Valery Ushakov
Niall Donovan  wrote:

> If you saw my follow up email, you will notice that I identified the code
> that is causing my problem. It is caused by the line of code at line 1146
> in tcp_out.c (Note I have LWIP_CHECKSUM_ON_COPY = 1)
> "acc += (u16_t)~(seg->chksum);"
> 
> acc is a one's compliment checksum obtained from a call to
> inet_chksum_pseudo_partial()
> and seg->chksum is a checksum of the payload.
> What is happening is that occasionally during operation acc is resulting in
> a value of M and seg->chksum has, by coincidence, a value of M. Then M +
> (~M) always gives 0x.
> 
[...] 
> Mathematically speaking using ones compliment maths, ~(sum(a+b+c+d)) is not
> the same as [(~sum(a+b)) + (~sum(c+d))] for the special corner case where
> sum(a+b) = ~sum(c+d). In this special case the answer will be 0x
> instead of 0x. Which is what is happening in my case!

Your analysis is correct.


As for the likelihood of stumbling into just the right numbers I
recently had an interesting problem.  I have a diskless machine that
has been running off NFS.  For ages.  After NFS server upgrade the
diskless machine would reliably wedge quite early in the boot process.

Eventually I tracked it down to a hardware checksum bug in the
ethernet of the diskless machine.  In UDP the checksum value 0 means
no checksum and if the datagram data actually has checksum 0, it's
replaced with 0x - which gives the same result if verification is
done properly (computing the sum with checksum filed included).
Apparently hardware checksum used recomute and compare method instead,
so it flagged such valid UDP datagrams as having a bad checksum.

The hardware bug has always been there and I've never seen it.  Then
when NFS server change changed the numerology of the NFS handles just
right, the bug was triggered reliably by some particular NFS response
datagram.

So don't underestiamte luck as a factor in system stability :)

-uwe


___
lwip-users mailing list
lwip-users@nongnu.org
https://lists.nongnu.org/mailman/listinfo/lwip-users


Re: [lwip-users] tcp_output() when processing "tcp_input_pcb"

2013-08-12 Thread Valery Ushakov
Numb_Faith  wrote:

> When I use lwip1.4.1 and RAW API, I meet a problem. I use my borad(STM32) as
> a server. When server receive a packet from client, I hope it can send a
> packet immediately. So I call the function below:
> 
> /tcp_write(tpcb, DataTest, sizeof(DataTest), 0x01);
> tcp_output(tpcb);/
> 
> But when server receive a packet, the stack will call tcp_input(), and
> tcp_input_pcb = pcb (the connection), so tcp_output(tpcb) would return.
> 
> When I comment the code below(in function tcp_output), it can got what I
> want. But I'm still confused about why "If we are invoked by the TCP input
> processing code, we do not output anything".
> 
> /* First, check if we are invoked by the TCP input processing code. If so,
> we do not output anything. 
>Instead, we rely on the input processing code to call us when input
> processing is done with. */
> //  if (tcp_input_pcb == pcb) {
> //  return ERR_OK;
> //  } 

Input processing code _does_ call tcp_output() at:

http://git.savannah.gnu.org/cgit/lwip.git/tree/src/core/tcp_in.c?h=DEVEL-1_4_1#n381

tcp_input_pcb = NULL;
/* Try to send something out. */
tcp_output(pcb);

At that point input processing is complete and pcb is in consistent
state, etc, etc, so tcp_output() doesn't have to be concerned with
possible iteractions with tcp_input().

-uwe


___
lwip-users mailing list
lwip-users@nongnu.org
https://lists.nongnu.org/mailman/listinfo/lwip-users


Re: [lwip-users] Sequence bug in core/tcp.c

2013-07-25 Thread Valery Ushakov
Joe Gorse  wrote:

> Around line 524 of core/tcp.c, in tcp_listen_with_backlog(struct tcp_pcb
> *pcb, u8_t backlog):
> 
>  LWIP_ERROR("tcp_listen: pcb already connected", pcb->state == CLOSED,
> return NULL);
> 
>  /* already listening? */
>  if (pcb->state == LISTEN) {
>return pcb;
>  }
> 
> A pcb->state == LISTEN never makes it past the LWIP_ERROR. Put the check
> for the LISTEN state above the LWIP_ERROR.
> 
> I am surprised anyone gets tcp_listen() to work at all for the raw
> API with this bug.

You are not supposed to call tcp_listen twice on the same pcb, so
everyone "get it to work at all" by not doing that :)

-uwe


___
lwip-users mailing list
lwip-users@nongnu.org
https://lists.nongnu.org/mailman/listinfo/lwip-users


Re: [lwip-users] where should I call tcp_accepted?

2013-05-10 Thread Valery Ushakov
CHASE CHENG  wrote:

> I added the tcp_accepted in my tcp_accept callback function, but it shows
> fail since pcb->state is already changed to ESTABLISHED.
> I wondered where should I call tcp_accepted?
[...]
> Here is part of the code:
> static err_t
> netio_accept(void *arg, struct tcp_pcb *pcb, err_t err)
> {
> ...
>  tcp_accepted(pcb);
> 
> I tried to add tcp_accepted here.

accept callback gets the new, connected, pcb that is in ESTABLISHED
state.  tcp_accepted should be called on the listening pcb, that is in
LISTEN state.

-uwe


___
lwip-users mailing list
lwip-users@nongnu.org
https://lists.nongnu.org/mailman/listinfo/lwip-users


Re: [lwip-users] serious lwIP 1.4.0 error

2013-04-03 Thread Valery Ushakov
Peter Sprenger  wrote:

>> Peter Sprenger  wrote:
> 
>>> The lwIP 1.4.0 problem is (I am using raw API), that lwIP gets a
>>> [FIN,ACK] from the other side (Firefox), but instead of doing a
>>> tcp_sent callback, it resubmits 3 times the packet that was already
>>> acked in the [FIN,ACK]. This leads to a hanging half-closed situation.
>>> Only after some minutes the Firefox on the PC will close the
>>> connection. Do you know if this has been fixed?
> 
>> Stupid question, but are you sure the FIN|ACK datagram actually
>> reaches lwIP tcpip thread?  You may be out of MEMP_NUM_TCPIP_MSG_INPKT.
>> I ran into this a few times with similar symptoms - lwIP would
>> retransmit data that looks ACKed if you only check the tcpdump trace.
> 
> I am not sure. Since I use no RTOS "NO_SYS" is defined to "1" and then
> the "MEMP_NUM_TCPIP_MSG_INPKT" parameter is not used. What have I to
> change then?

Can you verify that no packets were dropped on the path from the
network card to the lwIP tcpip thread?  MEMP_NUM_TCPIP_MSG_INPKT is
just an example of why a packet may be dropped.

-uwe


___
lwip-users mailing list
lwip-users@nongnu.org
https://lists.nongnu.org/mailman/listinfo/lwip-users


Re: [lwip-users] serious lwIP 1.4.0 error

2013-04-03 Thread Valery Ushakov
Peter Sprenger  wrote:

> The lwIP 1.4.0 problem is (I am using raw API), that lwIP gets a
> [FIN,ACK] from the other side (Firefox), but instead of doing a
> tcp_sent callback, it resubmits 3 times the packet that was already
> acked in the [FIN,ACK]. This leads to a hanging half-closed situation.
> Only after some minutes the Firefox on the PC will close the
> connection. Do you know if this has been fixed?

Stupid question, but are you sure the FIN|ACK datagram actually
reaches lwIP tcpip thread?  You may be out of MEMP_NUM_TCPIP_MSG_INPKT.
I ran into this a few times with similar symptoms - lwIP would
retransmit data that looks ACKed if you only check the tcpdump trace.

-uwe


___
lwip-users mailing list
lwip-users@nongnu.org
https://lists.nongnu.org/mailman/listinfo/lwip-users