eclipse-threadx / netxduo

Eclipse ThreadX - NetXDuo is an advanced, industrial-grade TCP/IP network stack designed specifically for deeply embedded real-time and IoT applications
https://github.com/eclipse-threadx/rtos-docs/blob/main/rtos-docs/netx-duo/index.md
MIT License
242 stars 137 forks source link

No answer to ICMP Echo requests when using PPP #100

Closed marcin-de closed 2 years ago

marcin-de commented 2 years ago

If NetX uses PPP as network interface, it does not respond to ICMP Echo requests sent from network. In fact, ICMP Echo requests are received by stack and processed (in _nx_icmpv4_process_echo_request function), but when responses are passed down to PPP stack, _nx_ppp_process_deferred_ip_packet_send function ends up with error when checking for available space for IPCP header, right here:

` / Determine if there is room in the front of the packet for the PPP header. / if ((packet_ptr -> nx_packet_prepend_ptr - packet_ptr -> nx_packet_data_start) < 2) {

        /* Error, there is no room at the front of the packet to prepend the PPP header.  */

ifndef NX_PPP_DISABLE_INFO

        /* Increment the internal error counter.  */
        ppp_ptr -> nx_ppp_internal_errors++;

endif

        /* Release the NetX packet.  */
        nx_packet_transmit_release(packet_ptr);

        /* An error was detected, simply return a NULL pointer.  */
        return;
    }

` It seems that higher level functions don't provide needed room for header, hence packet is dropped. Other than that, PPP interface works OK (at least with UDP traffic).

bo-ms commented 2 years ago

Hi @marcin-de, interesting, there should be four bytes available for ppp (IPCP header is two bytes), could you debug the code as below? let me know what you find. Thanks.

  1. Set breakpoint here in _nx_icmpv4_process_echo_request(), then watch packet_ptr->nx_packet_prepend_ptr and packet_ptr->nx_packet_data_start, check if the value of (packet_ptr->nx_packet_prepend_ptr - packet_ptr->nx_packet_data_start) is 24,

  2. Set breakpoint here in nx_ip_packet_send() to check the logic of adding IP header (20 bytes), watch the same variables and check if the value of (packet_ptr->nx_packet_prepend_ptr - packet_ptr->nx_packet_data_start) is 4,

  3. After adding IP header and before adding IPCP header, no data need to be added into packet, set breakpoint here to check if the value (packet_ptr->nx_packet_prepend_ptr - packet_ptr->nx_packet_data_start) is changed.

marcin-de commented 2 years ago

Hello, @bo-ms

Regarding above checks:

  1. Difference between packet_ptr->nx_packet_prepend_ptr and packet_ptr->nx_packet_data_start is 20 bytes, not expected 24 bytes.
  2. Difference here is zero bytes
  3. Again, difference here is zero bytes.
marcin-de commented 2 years ago

ppp

bo-ms commented 2 years ago

Hi @marcin-de Before IP header, there should be five bytes: three bytes (0x7e, 0xff, 0x03) for HDLC, and two bytes for (0x00, 0x21) for IPCP protocol, then move one byte to keep four bytes alignment before calling IP receive, could you set breakpoint to check it and share your data between data_start pointer and prepend_ptr pointer? Thanks.

image

marcin-de commented 2 years ago

Hi @bo-ms,

In my case, things look like this:

ppp2

So there are only three bytes before IP header. Why? This brings us to another "issue" with PPP stack: if during PPP connection setup remote peer requests LCP option 0x08 (Address-and-Control-Field-Compression), local stack accepts it - but later, when remote peer sends IPCP/IP packets with "compressed" fields (i.e. 0xFF and 0x03 bytes are not present), local stack still assumes that these bytes are present(!) and tries to remove them (it is done here ). This, of course, leads to "misalignment" in payload of IPCP packets and consequently to inability to set up PPP session. This was my first problem with PPP stack - and I solved it by replacing above code with this:

`

        if ((packet_head_ptr -> nx_packet_prepend_ptr[0] == 0x7e) &&
            (packet_head_ptr -> nx_packet_prepend_ptr[1] == 0xff) &&
            (packet_head_ptr -> nx_packet_prepend_ptr[2] == 0x03)
        ) {                                                                 // ** Full HDLC header present - remove
            packet_head_ptr -> nx_packet_prepend_ptr += 3;
            packet_head_ptr -> nx_packet_length -= 3;
        } else {                                                            // ** header not present (IPCP with compression?) - remove only start flag
            packet_head_ptr -> nx_packet_prepend_ptr += 1;
            packet_head_ptr -> nx_packet_length -= 1;
        }

` This brought PPP stack to work - it can negotiate the connection, gets IP address and IP stack is able to use the connection (UDP communication works OK). However, it seems that there are other places in PPP stack where assumption is made that received PPP frame always begins with 0x7E 0xFF 0x03...

bo-ms commented 2 years ago

Hi @marcin-de you are right, the Address and Control fields may be compressed, we will fix this issue in next release, you are able to fix it locally for testing, thanks for reporting this issue.

marcin-de commented 2 years ago

Hi @bo-ms Thanks for feedback. However... As I dig deeper into PPP specification, I'm getting the feeling that it is not an issue with PPP stack, but with modem itself...

Below is dump of PPP frames during establishment of connection. Lines with "<" show data from CPU to modem, lines with ">" - from modem to CPU.

<7EFF03 C021 01 2C 0008 010405DC 9D8C7E
<7EFF03 C021 01 2D 0008 010405DC 48137E
>7EFF03 C021 01 01 0018 020600000000 0304C023 050654FD4A65 0702 0802 A9067E
<7EFF03 C021 04 01 0008 0304C023 2CD47E
>7EFF03 C021 02 2D 0008 010405DC 98997E
>7EFF03 C021 01 02 0014 020600000000 05061121D847 0702 0802 111F7E
<7EFF03 C021 02 02 0014 020600000000 05061121D847 0702 0802 FA767E
<7EFF03 8021 01 2E 0016 030600000000 810600000000 830600000000 FD317E
>7E 8021 01 03 0004 032C7E
<7EFF03 8021 02 03 0004 75277E
>7E 8021 03 2E 0016 03060A0A2409 810600000000 830600000000 26007E
<7EFF03 8021 01 2F 0016 03060A0A2409 810600000000 830600000000 81FD7E
>7E 8021 02 2F 0016 03060A0A2409 810600000000 830600000000 179E7E

Third line is ConfReq from modem to stack with LCP option 0x08 present. Then stack rejects option 0x03 (auth protocol), so in line six modem resends ConfReq without rejected option and in line seven stack acknowledges rest of options (including 0x08). But, according to RFC, this means that Address and Control Field Compression may be used in direction from stack to modem, not the opposite - but instead modem starts to use compression(!?), which leads to "issues" in PPP stack. And stack itself still sends frames with full header (even if it knows that it can be omitted - but it does not matter). Furthermore, stack never requests LCP 0x08, so modem should not use the compression, in which case everything shall work as expected... Please consider if this is the case.

marcin-de commented 2 years ago

Quick followup. If I remove LCP option 0x08 from "known options list" here, so during parsing it falls to default and gets rejected, then modem sends IPCP/IP frames with full header and all, including ping, works as expected...

bo-ms commented 2 years ago

Hi @marcin-de Thanks for the update. From the spec below. This Configuration Option (ACFC) is sent to inform the peer that the implementation can receive compressed Address and Control fields. If our PPP client (CPU) did not send this option to modem, the modem should not send compressed data to PPP client (CPU). Looks the issue is in modem, not PPP stack, what do you think?

6.6. Address-and-Control-Field-Compression (ACFC)

Description

  This Configuration Option provides a method to negotiate the
  compression of the Data Link Layer Address and Control fields.  By
  default, all implementations MUST transmit frames with Address and
  Control fields appropriate to the link framing.

  Since these fields usually have constant values for point-to-point
  links, they are easily compressed.  This Configuration Option is
  sent to inform the peer that the implementation can receive
  compressed Address and Control fields.

  If a compressed frame is received when Address-and-Control-Field-
  Compression has not been negotiated, the implementation MAY
  silently discard the frame.

  The Address and Control fields MUST NOT be compressed when sending
  any LCP packet.  This rule guarantees unambiguous recognition of
  LCP packets.

  When the Address and Control fields are compressed, the Data Link
  Layer FCS field is calculated on the compressed frame, not the
  original uncompressed frame.
marcin-de commented 2 years ago

Yes, exactly, it looks like an issue with modem's firmware, not the PPP stack in NetX. I will report this to modem's manufacturer (Simcom), and you can close this issue.

Thanks for support!

bo-ms commented 2 years ago

closing, @marcin-de feel free to reopen it if you have any issue after discussion with Simcom.