LinuxQuestions.org
Review your favorite Linux distribution.
Home Forums Tutorials Articles Register
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 09-28-2009, 02:58 PM   #1
yaplej
Member
 
Registered: Apr 2009
Distribution: CentOS, Ubuntu, openSuSE
Posts: 165
Blog Entries: 1

Rep: Reputation: 22
Reading TCP Option inconsistant output.


I have made a function that I am using in a Kernel Module. The fucntion reads the data field of the TCP option you want. It will either return the data value as a 64-bit integer, return 1 if the option is present, but has no data, or return 0 if the option is not present.

I am testing with the TCP Option for MSS ie option 2. Its length is 4 bytes. Byte1 = its option number 2, Byte 2 = its length 4, and Byte 3&4 are a 16-bit integer value. Default is 1460.

If I request this option value with my function it returns "1460", but then I set it to 1460 - 60 or 1400 WireShark shows that its set correctly, but when I try to read it again with my fuction it returns "1404"

Now I tried setting it to 1460 - 64, and behold it works correctly again. So what could cause this to return incorrect data for these specific values?

Edit:
I tried a whole bunch of different data values, and 1400 is the only one with the problem so far.

1460 OK = 1460
1400 BAD = 1404
1396 OK = 1396
1300 OK = 1300
1404 OK = 1404
1340 OK = 1340
Code:
#include <linux/autoconf.h>
#include <linux/netdevice.h>
#include <linux/if_ether.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/tcp.h>

#include <net/protocol.h>
#include <net/pkt_sched.h>
#include <net/ip.h>
#include <net/tcp.h> /* Needed for tcpmagic and TCP Options */



static inline unsigned int
optlen(const u_int8_t *opt, unsigned int offset)
{
	if (opt[offset] <= TCPOPT_NOP || opt[offset+1] == 0)
		return 1;
	else
		return opt[offset+1];
}

/*
 * yaplej: This function will attempt to locate
 * the requested tcp option from the passed skb.
 *
 * If it locates the tcp option it will then check its length
 * to determine if there is any option data to return.
 * If there is option data it will return that, and
 * if there is not data for the option it will return 1.
 *
 * If the option is not found it will return 0.
 */
static inline u_int64_t
__get_tcp_option(struct sk_buff *skb, unsigned int tcpoptnum)
{
	unsigned int i, tcpoptlen;
	struct tcphdr *tcph;
	struct iphdr *iph;
	u8 *opt;

	iph = ip_hdr(skb);
	tcph = (struct tcphdr *)(skb_network_header(skb) + ip_hdrlen(skb));
	opt = (u_int8_t *)tcph + sizeof(struct tcphdr);

		for (i = 0; i < tcph->doff*4 - sizeof(struct tcphdr); i += optlen(opt, i)) {
			if (opt[i] == tcpoptnum) {

				tcpoptlen = opt[i+1]; // get option length.

				if ((tcph->doff*4 - i >= tcpoptlen) &&
				(opt[i+1] == tcpoptlen)) {

					u_int64_t tcpoptdata;
					u_int8_t bytefield;
					u_int8_t count;

					/* if the option exists, but data length is 2  */
					if (tcpoptlen == 2)
						return 1;
					else

					count = tcpoptlen - 2; // get option length,
										  // and ignore header fields.
					bytefield = 2;  // the first data byte is always at i+2.
					tcpoptdata = 0; // initialize tcpoptdata for compiler.



					while (count > 0) {
						count--;
						if ((count) != 0) {
							tcpoptdata += (opt[i+bytefield] << 8 * count);
						}
						else {
							tcpoptdata += opt[i+bytefield];
						}

					bytefield++;
					}

					tcpoptdata |= opt[i+bytefield] & 0xFE;

				return tcpoptdata;
				}
			}
		}

		return 0;
}

Last edited by yaplej; 09-28-2009 at 03:11 PM.
 
Old 09-29-2009, 11:48 PM   #2
smeezekitty
Senior Member
 
Registered: Sep 2009
Location: Washington U.S.
Distribution: M$ Windows / Debian / Ubuntu / DSL / many others
Posts: 2,339

Rep: Reputation: 231Reputation: 231Reputation: 231
do you mean TCP IP if not i have no clue what you are talkng about
 
Old 09-30-2009, 12:50 AM   #3
yaplej
Member
 
Registered: Apr 2009
Distribution: CentOS, Ubuntu, openSuSE
Posts: 165

Original Poster
Blog Entries: 1

Rep: Reputation: 22
Yes, I am talking about the Transmission Control Protocol in TCP/IP.
 
Old 09-30-2009, 12:56 AM   #4
smeezekitty
Senior Member
 
Registered: Sep 2009
Location: Washington U.S.
Distribution: M$ Windows / Debian / Ubuntu / DSL / many others
Posts: 2,339

Rep: Reputation: 231Reputation: 231Reputation: 231
WELL {
A :: your code is exccessivly indented but its ok
B :: are you sure the opt array is set correctly?; not quite sure where it comes from
}

*And yes i have been programming WAY to long and my text looks like programming;
 
Old 09-30-2009, 01:37 AM   #5
yaplej
Member
 
Registered: Apr 2009
Distribution: CentOS, Ubuntu, openSuSE
Posts: 165

Original Poster
Blog Entries: 1

Rep: Reputation: 22
Excessive indenting helps me debug, and easier for me to read. It’s taken a week to get my two functions semi-working and not crashing the kernel.

Opt is set correctly, and this works 99% of the time it’s just where the data field = 1400 where it’s not working.

Well at least that I have found so far. Because the data field can be between 0-bits to 64-bit I have not tested every possibility, but I have only found this one for sure that it’s screwed up.

Its reading two bytes that as an integer = 1400 the byte values are 00000101 & 01111000 if I understand the code correctly the first byte is read as 5, and then left shifted 8 places turning 5 into 1280. Then the second (and last in this case) byte field is read as 120, and added to tcpoptdata value. So at this point it should = 1400.

Next I do this, and honestly I don’t know why, but it was in my example so I left it in there.


Code:
tcpoptdata |= opt[i+bytefield] & 0xFE;
 
Old 09-30-2009, 01:42 AM   #6
smeezekitty
Senior Member
 
Registered: Sep 2009
Location: Washington U.S.
Distribution: M$ Windows / Debian / Ubuntu / DSL / many others
Posts: 2,339

Rep: Reputation: 231Reputation: 231Reputation: 231
i think i gave that to you
& 0xFE repairs an error with the one'th bit
and will not cause your problem
but it assumes opt is 1 byte in size
you could use the cheater way out by using an if statement
so if you request 1400 it will manually correct the error
 
Old 09-30-2009, 11:49 AM   #7
yaplej
Member
 
Registered: Apr 2009
Distribution: CentOS, Ubuntu, openSuSE
Posts: 165

Original Poster
Blog Entries: 1

Rep: Reputation: 22
I am not sure what the one'th bit error is, but I definatly dont want to take the cheater way out, and manually correct it.

Opt is a pointer to the first byte of either the TCP options or the TCP data. If tcph->doff is > 5 its going to point to the first byte of TCP options if tcph->doff is == 5 then there are no TCP options, and its going to point at the first byte of TCP data. In that case I dont do anything with the options because there are none, and the function just returns 0 because no options exist in the TCP segment.
 
Old 09-30-2009, 12:29 PM   #8
yaplej
Member
 
Registered: Apr 2009
Distribution: CentOS, Ubuntu, openSuSE
Posts: 165

Original Poster
Blog Entries: 1

Rep: Reputation: 22
Well I took out that unknown bit of code, and it works now for the value of 1400, and has not broken the other values so far. I still need to do a little more validation to make sure its all ok, but it does not seem to be needed.

Code:
tcpoptdata |= opt[i+bytefield] & 0xFE;
 
  


Reply



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
[SOLVED] Problem writing new tcp option to skb yaplej Programming 3 08-17-2011 07:24 AM
[DD-WRT] Reading TCP-Packets via TCPDUMP trough SSH zeroXcool Linux - Networking 6 03-05-2009 01:14 PM
how to swtich off the -nolisten TCP option of X in fedora 9 nkd Fedora 1 12-28-2008 09:32 AM
Samba - weird issue - inconsistant? sternfan Linux - Networking 4 04-17-2006 11:29 PM
TCP Keep alive Option Performance impact ndwivedi Linux - Software 0 06-24-2004 01:58 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 07:20 PM.

Main Menu
Advertisement
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
Open Source Consulting | Domain Registration