LinuxQuestions.org
Did you know LQ has a Linux Hardware Compatibility List?
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 01-06-2010, 09:26 PM   #1
SeymourButts
LQ Newbie
 
Registered: Jan 2010
Posts: 28

Rep: Reputation: 15
Question Porting C Program to Linux & Problem with Size of ICMP Packet


I have a C program that has been running for years on Solaris platform. I have compiled it on Linux 2.6 successfully.

The program sits on a RAW socket and continually waits and processes custom ICMP packets that arrive from different devices.

When the recvfrom() drops through from an incoming packet, the return (rc) says it read a 256 byte icmp type packet that I sent in. That's all good.

I pass the recvfrom buffer to a function and cast it to a struct ip pointer. At this point, when I check the size of the packet using ip_len, it now shows 5121 bytes as the packet size.

I don't understand how the packet grew from 256 bytes to 5121 byes. I am really out of ideas on why this is happening. On Solaris, the packet size is what is should be but not on Linux.

Any ideas you may have would be very helpful. Thank you.

I will include the main code pieces below.

Code:
char recv_buffer [8184];
..
icmp_sd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
..
setsockopt(icmp_sd,SOL_SOCKET,SO_RCVBUF,(char *)&iReceive,sizeof(iReceive));
..
rc = recvfrom (icmp_sd, recv_buffer, iLen,iFlag,&sFrom, &iFromLen);
..
printf(log_message,"Packet Arrived. Bytes Read:[%d]\n",rc); /* 256 bytes */
..
recv_buffer[rc] = '\0';
..
process_msg(recv_buffer, icmp_sd);

/* Function */
int process_msg (char *buffer, int iFd)
{
struct ip *ip_rcv_ptr; 
..
/* Initialize IP pointer */
ip_rcv_ptr = (struct ip *) buffer;
..
printf("Length of Packet: %d\n", ip_rcv_ptr->ip_len); /* 5121 bytes */
..
}

Last edited by SeymourButts; 01-07-2010 at 06:34 AM.
 
Old 01-07-2010, 06:09 AM   #2
SeymourButts
LQ Newbie
 
Registered: Jan 2010
Posts: 28

Original Poster
Rep: Reputation: 15
Crap, I meant to post this in the programming forum. I would be overjoyed if a moderator would move this to the programming forum.
 
Old 01-07-2010, 01:49 PM   #3
orgcandman
Member
 
Registered: May 2002
Location: dracut MA
Distribution: Ubuntu; PNE-LE; LFS (no book)
Posts: 594

Rep: Reputation: 102Reputation: 102
A few nits.
Code:
char recv_buffer [8184];
Make this 2048. While it's *possible* to receive a packet that is > 2048 bytes, in practice you'll rarely find packets exceeding roughly 1490. 2048 is nice and "round" and does the job just fine. (additionally, an 8k memory region on the stack is a pagefault waiting to happen)

Code:
..
setsockopt(icmp_sd,SOL_SOCKET,SO_RCVBUF,(char *)&iReceive,sizeof(iReceive));
Would be nice to see what you set the receive buffer size to be.

Code:
..
rc = recvfrom (icmp_sd, recv_buffer, iLen,iFlag,&sFrom, &iFromLen);
What are your flags?

Code:
..
recv_buffer[rc] = '\0';
Why are you doing this? No need to 0 out packet buffer contents. You're not using str*() operations (right?)

Code:
..
printf("Length of Packet: %d\n", ip_rcv_ptr->ip_len); /* 5121 bytes */
ntohs() baby!

You'll need to remember to change network order to host order. Unless your machine is big endian.

-Aaron
 
Old 01-07-2010, 02:59 PM   #4
SeymourButts
LQ Newbie
 
Registered: Jan 2010
Posts: 28

Original Poster
Rep: Reputation: 15
Thanks for the reply. Receive buffer size is set to the same 8184 as the recv_buffer char array.

How to check if server is big endian?

Status Update:

I found out that there seems to be differences in data types in the ip & icmp structs between Solaris & Linux. Too bad the structs don't use the same data types.

On Solaris, struct ip.ip_len is a short and on Linux it's a u_short. Honestly, I am not clear on the difference, but clearly it is causing issues. I assume other members of struct ip or struct icmp are also causing me heartaches.

I added the following htons() call which did shrink the ip_len down to a size I was expecting. However, I am still having issues with memory faults due to differences in sizes.

Code:
/* Initialize IP pointer */
ip_rcv_ptr = (struct ip *) buffer;

/* Convert ip_len */
ip_rcv_ptr->ip_len = htons(ip_rcv_ptr->ip_len);

Last edited by SeymourButts; 01-07-2010 at 03:09 PM.
 
Old 01-08-2010, 03:25 AM   #5
jf.argentino
Member
 
Registered: Apr 2008
Location: Toulon (France)
Distribution: FEDORA CORE
Posts: 492

Rep: Reputation: 50
Quote:
How to check if server is big endian?
You don't have to! Data exchange over ethernet must be done in big endian, that's the law. Since ultra-sparc cpu are big-endian, you never see this bug until you port your code on a littl-endian system (x86 cpu). By the way, if you really need to know which endianness is used, use macro defined in <endian.h>.

Quote:
On Solaris, struct ip.ip_len is a short and on Linux it's a u_short. Honestly, I am not clear on the difference, but clearly it is causing issues
"u_short" goes from 0 to 65535, "short" goes from -32768 to 32767. And the bug is Solaris side since the maximum IP length _IS_ 65536 bytes. But I don't think this is causing any issue in your case since you don't use size over 32767 bytes...
 
Old 01-08-2010, 06:31 AM   #6
SeymourButts
LQ Newbie
 
Registered: Jan 2010
Posts: 28

Original Poster
Rep: Reputation: 15
If I don't adjust ip.ip_len using htons() then the number of bytes is 5121 even though the number of bytes read off socket is 256.

Code:
rc = recvfrom (icmp_sd, recv_buffer, iLen,iFlag,&sFrom, &iFromLen);

printf("Bytes Read=%d\n",rc); /* 256 bytes */

/* Initialize IP pointer */
ip_rcv_ptr = (struct ip *) recv_buffer;

printf("Before htons() ip_len=%d\n", ip_rcv_prt->ip_len); /* 5151 */

/* Convert ip_len */
ip_rcv_ptr->ip_len = htons(ip_rcv_ptr->ip_len);

printf("After htons() ip_len=%d\n", ip_rcv_prt->ip_len); /* 256 */
Maybe calling htons() is really just a bandaid for some other issue that I have not discovered yet. Using htons() appears to correct the length of the packet pulled off the socket.

I can't tell you how long I have been trying to get this working correctly on Linux.

Last edited by SeymourButts; 01-08-2010 at 06:33 AM.
 
Old 01-08-2010, 09:34 AM   #7
SeymourButts
LQ Newbie
 
Registered: Jan 2010
Posts: 28

Original Poster
Rep: Reputation: 15
Now I am really confused. If I am sending an icmp packet to my program from a test program the byte order should not be an issue because both programs are compiled and running on the same Linux server (little endian).

I still can't explain why the the ip_rcv_ptr->ip_len is 5121 bytes after setting it to a struct ip ptr when the size of the packet read is 256 bytes. So frustrating.
 
Old 01-08-2010, 09:51 AM   #8
jf.argentino
Member
 
Registered: Apr 2008
Location: Toulon (France)
Distribution: FEDORA CORE
Posts: 492

Rep: Reputation: 50
Because, on sending part, the IP stack handle the endianness to be conform to the ETHERNET spec, then when it create the IP header, its content is in big endian, as is the transport header (icmp, tcp, udp..., maybe not the transport layer, I'm not an OSI guru)
 
Old 01-08-2010, 01:35 PM   #9
SeymourButts
LQ Newbie
 
Registered: Jan 2010
Posts: 28

Original Poster
Rep: Reputation: 15
I think I may have a grasp of what I need to do.

If I am sending a packet, I need to use htons() or htonl() on the int or byte members of struct ip or struct icmp.

If I am receiving a packet, I need to use ntohs() or ntohl() on the int or byte members of struct ip or struct icmp.

Plan on giving that a try later to see if fixes the problem.
 
Old 01-11-2010, 02:15 AM   #10
jf.argentino
Member
 
Registered: Apr 2008
Location: Toulon (France)
Distribution: FEDORA CORE
Posts: 492

Rep: Reputation: 50
Quote:
If I am sending a packet, I need to use htons() or htonl() on the int or byte members of struct ip or struct icmp.

If I am receiving a packet, I need to use ntohs() or ntohl() on the int or byte members of struct ip or struct icmp.
That's almost it... But htons and ntohs doesn't apply to bytes but shorts (16bits), bytes does not have endianness...
I recall you that you need to do this on the ip / icmp headers since you're using RAW socket level.
A last clue, use int8_t, int16_t,.. types family, defined in stdint.h
 
Old 01-15-2010, 07:53 AM   #11
SeymourButts
LQ Newbie
 
Registered: Jan 2010
Posts: 28

Original Poster
Rep: Reputation: 15
Quote:
Originally Posted by jf.argentino View Post
That's almost it... But htons and ntohs doesn't apply to bytes but shorts (16bits), bytes does not have endianness...
I recall you that you need to do this on the ip / icmp headers since you're using RAW socket level.
A last clue, use int8_t, int16_t,.. types family, defined in stdint.h
Can you explain a little more about "use int8_t, int16_t"?
 
Old 01-15-2010, 08:06 AM   #12
jf.argentino
Member
 
Registered: Apr 2008
Location: Toulon (France)
Distribution: FEDORA CORE
Posts: 492

Rep: Reputation: 50
When you need to specify a type by its size, using int8_t, int16_t... is the only reliable way to do it since the C99 standard doesn't require that "sizeof (char) == 1", "sizeof (short) == 2" nor "sizeof (long) == 4". For example, with gcc, long are 32 bits on fedora 32 bits, and 64 bits on fedora 64 bits.
These type are mandatory for a (reasonable) C99 conformant compiler / standard library, see <stdint.h> for more details.
 
  


Reply

Tags
icmp, packet, socket


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Sending ICMP messages of type 3 when packet size exceeds MTU of the interface nmb1081 Linux - Networking 1 04-13-2008 10:14 PM
New ICMP Packet Creation kaustubh_pict Linux - Networking 2 03-02-2006 12:00 PM
Why ICMP packet for ping and nmap. bruse Linux - Networking 2 12-12-2005 09:48 AM
ICMP Packet capture SaTaN Programming 1 01-19-2004 11:38 PM
ICMP packet requests Ch@meleon Linux - General 0 11-29-2001 12:03 PM


All times are GMT -5. The time now is 09:43 PM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration