Guru Q: recvfrom on IP_HDRINCL socket

Guru Q: recvfrom on IP_HDRINCL socket

Post by Jens Schweikhard » Sat, 19 Oct 2002 22:24:52



(Note: Xpost and fup2 comp.unix.programmer)

hello, world\n

I'm porting an OPSF implementation to an embedded system (pSOS 2.5, which
claims it's IP stack is derived from 4.3BSD) and observe the following
puzzling behavior. I wonder whether it's a bug in the OS, in my code, or
a misunderstanding:

I use a raw socket to receive and send OSPF packets and set the
IP_HDRINCL option:

    // Open network
    if ((netfd = socket(AF_INET, SOCK_RAW, PROT_OSPF)) == -1) {
        do_log(LOG_ERR, "Network open failed: %d", errno);
        exit(1);
    }
    // We will supply headers on output and want them on input
    int hincl = 1;
    if (setsockopt(netfd, IPPROTO_IP, IP_HDRINCL,
                   (char *)&hincl, sizeof(hincl)) != 0) {
        do_log(LOG_ERR, "setsockopt: IP_HDRINCL, pNA error %#x", errno);
        exit(1);
    }

Sending my own assembled OSPF packets is no problem. Reception however
is mysterious. I use

    char buffer[65536];
    int plen;
    int fromlen;
    plen = recvfrom (netfd, buffer, sizeof (buffer), 0, 0, &fromlen);
    if (plen < 0) {
        do_log (LOG_ERR, "recvfrom: %d", errno);
        return;
    }

At this point, the buffer has the packet, including the IP header - so
far so good. However, the value plen as returned from recvfrom is not
the same as the one indicated in the IP header. The IP header's length
field is 20 less than plen, e.g. not accounting for the IP header length
itself: Say, plen is 88, while the 16 bit value at buffer+3 is 68 (big
endian system, so no, it's not a network order vs machine byte order
problem). According to rfc 791 (IP) the length is the total length
including the header.

Question: is it allowed behavior that the return value from recvfrom
          can be different from the packet's IP header?

Regards,

        Jens
--
Jens Schweikhardt  http://www.schweikhardt.net/
SIGSIG -- signature too long (core dumped)

 
 
 

Guru Q: recvfrom on IP_HDRINCL socket

Post by Jeremie LE HE » Wed, 23 Oct 2002 12:35:02


Quote:> Question: is it allowed behavior that the return value from recvfrom
>           can be different from the packet's IP header?

There is no 4.3BSD based system on which I have a shell so I cannot do my
own tests, but here is a portion of the recvfom(2) manual [4.3-Reno
Berkeley Distribution February 1, 1994 3] :

--- cut here ---
int
recvfrom(int s, void *buf, int len, int flags, struct sockaddr *from,
         int *fromlen)

[...]

If from is non-nil, and the socket is not connection-oriented, the source
address of the message is filled in. Fromlen is a value-result parameter,
initialized to the size of the buffer associated with from, and modified
on return to indicate the actual size of the address stored there.
--- cut here ---

On the other hand, here is the same portion of the same manpage from my
box [FreeBSD 4.6 February 21, 1994] :

--- cut here ---
ssize_t
recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from,
         socklen_t *fromlen);

[...]

If from is non-nil, and the socket is not connection-oriented, the source
address of the message is filled in.  Fromlen is a value-result parame-
ter, initialized to the size of the buffer associated with from, and mod-
ified on return to indicate the actual size of the address stored there.
--- cut here ---

And finally the manual page from [NetBSD 1.5.2 February 21, 1994] says
exactly the same description as above.

I didn't succeed in finding struct sockaddr declaration of a 4.3BSD system
but I'm pretty sure that it has a field named sa_len which represents the
size of the `from' pointing buffer. This should be equal to what you get
in the `fromlen' out parameter.

The return value is just the size of the message you received. I mean
there is no arithmetic rule which says this buffer should be 20 bytes
greater than the size of the buffer pointed by `from'. There is no
relation _at all_ between there two values.

Regards
--
Jeremie LE HEN aka T{ata,t}Z


 
 
 

Guru Q: recvfrom on IP_HDRINCL socket

Post by Tony Tan » Wed, 23 Oct 2002 15:18:28



Quote:> Sending my own assembled OSPF packets is no problem. Reception however
> is mysterious. I use

>    char buffer[65536];
>    int plen;
>    int fromlen;
>    plen = recvfrom (netfd, buffer, sizeof (buffer), 0, 0, &fromlen);
>    if (plen < 0) {
>        do_log (LOG_ERR, "recvfrom: %d", errno);
>        return;
>    }

> At this point, the buffer has the packet, including the IP header - so
> far so good. However, the value plen as returned from recvfrom is not
> the same as the one indicated in the IP header. The IP header's length
> field is 20 less than plen, e.g. not accounting for the IP header length
> itself: Say, plen is 88, while the 16 bit value at buffer+3 is 68 (big
> endian system, so no, it's not a network order vs machine byte order
> problem). According to rfc 791 (IP) the length is the total length
> including the header.

> Question: is it allowed behavior that the return value from recvfrom
>          can be different from the packet's IP header?

The value returned from recvfrom and the value of length field in the
ip header are two different things.

Return value means the total number of bytes that are written into
buffer(or in other word, received).

The length field in ip header means the total length of the data(in the IP
packet, not including IP header).

--
Tony Tang             | FreeBSD fan
Tel: +86 28 8320 4707 | PGP key available

 
 
 

Guru Q: recvfrom on IP_HDRINCL socket

Post by Jens Schweikhard » Wed, 23 Oct 2002 15:59:17




#

#> Sending my own assembled OSPF packets is no problem. Reception however
#> is mysterious. I use
#>
#>    char buffer[65536];
#>    int plen;
#>    int fromlen;
#>    plen = recvfrom (netfd, buffer, sizeof (buffer), 0, 0, &fromlen);
#>    if (plen < 0) {
#>        do_log (LOG_ERR, "recvfrom: %d", errno);
#>        return;
#>    }
#>
#> At this point, the buffer has the packet, including the IP header - so
#> far so good. However, the value plen as returned from recvfrom is not
#> the same as the one indicated in the IP header. The IP header's length
#> field is 20 less than plen, e.g. not accounting for the IP header length
#> itself: Say, plen is 88, while the 16 bit value at buffer+3 is 68 (big
#> endian system, so no, it's not a network order vs machine byte order
#> problem). According to rfc 791 (IP) the length is the total length
#> including the header.
#>
#> Question: is it allowed behavior that the return value from recvfrom
#>          can be different from the packet's IP header?
# The value returned from recvfrom and the value of length field in the
# ip header are two different things.
#
# Return value means the total number of bytes that are written into
# buffer(or in other word, received).
#
# The length field in ip header means the total length of the data(in the IP
# packet, not including IP header).

I'm afraid this is not correct. Like I said, RFC 791 disagrees with your
last statement:

<QUOTE RFC 791, "Internet Protocol">

  Total Length:  16 bits

    Total Length is the length of the datagram, measured in octets,
    including internet header and data.  This field allows the length of
    a datagram to be up to 65,535 octets.

</QUOTE>

The original software was written for Linux, which relies on "retval
from recvfrom == ip total length". I think this is the correct behavior.
When ported to pSOS, everything works if I hack the code to explicitly
assign "ip total length" = "retval from recvfrom", but I want my
software to work by design and not by chance. This is why I ask for
clarification.

Regards,

        Jens
--
Jens Schweikhardt  http://www.schweikhardt.net/
SIGSIG -- signature too long (core dumped)

 
 
 

Guru Q: recvfrom on IP_HDRINCL socket

Post by Tony Tan » Wed, 23 Oct 2002 16:56:07



> I'm afraid this is not correct. Like I said, RFC 791 disagrees with your
> last statement:
You are right.
> The original software was written for Linux, which relies on "retval
> from recvfrom == ip total length". I think this is the correct behavior.
I suppose so.
> When ported to pSOS, everything works if I hack the code to explicitly
> assign "ip total length" = "retval from recvfrom", but I want my
> software to work by design and not by chance. This is why I ask for
> clarification.

You said pSOS's TCP/IP stack is based on 4.3BSD right?
I don't have a 4.3BSD, nor pSOS. Test if this is the case in 4.3BSD
If so, this might be bug(or whatever) in 4.3BSD. Checkout the 4.3
but-list. Where's one?

--
Tony Tang             | FreeBSD fan
Tel: +86 28 8320 4707 | PGP key available

 
 
 

Guru Q: recvfrom on IP_HDRINCL socket

Post by Jens Schweikhard » Thu, 24 Oct 2002 16:41:52




...
# You said pSOS's TCP/IP stack is based on 4.3BSD right?

Yup, that's what the documentation claims.

# I don't have a 4.3BSD, nor pSOS. Test if this is the case in 4.3BSD
# If so, this might be bug(or whatever) in 4.3BSD. Checkout the 4.3
# but-list. Where's one?

If anyone could point me to 4.3BSD source, that would be helpful. I'm
not sure if this code is encumbered (I think so, because it predates
4.4).

Regards,

        Jens
--
Jens Schweikhardt  http://www.schweikhardt.net/
SIGSIG -- signature too long (core dumped)

 
 
 

Guru Q: recvfrom on IP_HDRINCL socket

Post by Cezar Ionesc » Thu, 24 Oct 2002 18:54:24



Quote:> If anyone could point me to 4.3BSD source, that would be helpful. I'm
> not sure if this code is encumbered (I think so, because it predates
> 4.4).

        ftp://ftp.cs.tu-berlin.de/pub/bsd/UnixArchive/4BSD
 
 
 

Guru Q: recvfrom on IP_HDRINCL socket

Post by Jens Schweikhard » Fri, 25 Oct 2002 16:55:29




#

#> If anyone could point me to 4.3BSD source, that would be helpful. I'm
#> not sure if this code is encumbered (I think so, because it predates
#> 4.4).
#
#         ftp://ftp.cs.tu-berlin.de/pub/bsd/UnixArchive/4BSD

Thanks! That's a good resource.

Regards,

        Jens
--
Jens Schweikhardt  http://www.schweikhardt.net/
SIGSIG -- signature too long (core dumped)