Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: tcp/ip
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
vesago
Пытаюсь на меге гонять данные через GPRS. Не стал я пользовать готовые стеки типа айпи и лвп. Пишу свое приложение - порезаный tcp на нет. Так вот вопрос к тем кто разбирался с этой тематикой. Как правильно посчитать контрольную сумму для TCP пакета? Смотрел я упомянутые стеки. там для IP и TCP пакета вроде одинаковый алгоритм. Я позаимствовал их код. Снифером смотрел сетевой трафик в локалке - для TCP такой вариант не проходит - не сходится контрольная сумма.
Rst7
Цитата(vesago @ Oct 9 2006, 16:27) *
Пытаюсь на меге гонять данные через GPRS. Не стал я пользовать готовые стеки типа айпи и лвп. Пишу свое приложение - порезаный tcp на нет. Так вот вопрос к тем кто разбирался с этой тематикой. Как правильно посчитать контрольную сумму для TCP пакета? Смотрел я упомянутые стеки. там для IP и TCP пакета вроде одинаковый алгоритм. Я позаимствовал их код. Снифером смотрел сетевой трафик в локалке - для TCP такой вариант не проходит - не сходится контрольная сумма.


А ты не забыл, что в TCP есть еще псевдо-заголовок, который участвует в подсчете контрольной суммы, но не передается в канал связи?
vesago
Не забыл. Я перед расчетом инициализирую чексум числом 6 + длина TCP и натравляю процедуру на начало IP адресов в буфере. Попробовал за основу взять расчет IP чексум, но менять порядок 16 битных данных. Стала сходиться. Можно было-бы забить. но где гарантия, что в другой среде не будет проблем. Еще посомтрел в микроайпи и лвайпи не меняется порядок. Да и статью почитал одну в которой сказано, что от изменения порядка 16 битных опрерандов контрольной суммы изменяется толькло порядок байтов результата.
ktod
Делаю так:
inline u16 checksum(u8* d, int l, u32 c)
{
while(l > 1)
{ c += *(u16*)d;
d += 2; l -= 2;
}
if(l) c += *d;

c = (c >> 16) + (c & 0xffff);
c += (c >> 16);
u16 ret = ((u16)(~c));
return ret;
}

где вызов:

u32 ph = (saddr) & 0xffff) + ( (saddr) >> 16) +
((daddr) & 0xffff) + ((daddr) >> 16) +
0x600 + ((u16)l);

u16 cs = checksum(d, l, ph);
u32 saddr и пр. берется из ип хедера.
Это для тсп.

для удп:
u32 ph = (saddr) & 0xffff) + ( (saddr) >> 16) +
((daddr) & 0xffff) + ((daddr) >> 16) +
0x1100 + ((u16)l);

u16 cs = checksum(d, l, ph);

для ип еще проще:
u16 cs = checksum(d, ihl, 0);


Не забываем, что для ип сумма считается только для заголовка.
vesago
Спасибо, попробую.
Увы не сходится. Я смотрел снифером пакет:
Код
volatile unsigned char buf[] = {
0xC0, 0xA8, 0x01, 0x08,   //src addr
0xC0, 0xA8, 0x01, 0x0E,  //dst addr

0x11, 0x42, 0x13, 0x88,  //Сам TCP пакет всего 25 октетов
0x97, 0xD4, 0xA2, 0x11,
0x1B, 0x01, 0x1A, 0x63,
0x50, 0x18, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00,
0x31, 0x31, 0x31, 0x31, 0x31
};

Для него контрольная сумма 0x04EA. Может под нетбиосом как-то по другому считается?

Зато контрольная сумма сходится если посчитать этой процедуро предварительно tcp_crc = 6 + 25.
Код
void Calc_TCP_CRC(unsigned char *buf, unsigned int len, unsigned int *tcp_crc)
{
  unsigned long crc = *tcp_crc;
  unsigned int *ptr_to_buf = (unsigned int*)buf;
  unsigned int i, tmp;

  i = 0;
  do
  {
    tmp = (*(ptr_to_buf))>>8;
    tmp += (*(ptr_to_buf++))<<8;
    crc += tmp;
    i += 2;
  }while(i<len);

  if((len/2) & 1) crc += *((unsigned char*)ptr_to_buf);

  crc = (crc >> 16) + crc & 0xffff;
  crc += (crc >> 16);
  crc=(unsigned int)(~crc);

  *tcp_crc = (unsigned int)crc;
}

volatile unsigned int tcp_crc = 6 + 25;

Calc_TCP_CRC((unsigned char *)&buf, 33, (unsigned int *)&tcp_crc);


По сути дела она работает как и ваша. Просто хотелось бы иметь одну процедуру. которая считала бы и для IP и для TCP как в вашем случае. в приаттаченой статье тоже говорится что одна функция. Не могу понять чего у меня не работает.
ktod
Обратите внимание на 0x600 + ((u16)l) при расчете для тсп.
l - это длинна тсп пакета. т.е. длина используется два раза при расчете кс.

По сути дела строкой
volatile unsigned int tcp_crc = 6 + 25;
Вы это и делаете.

И если посмотреть на весь ip пакет будет понятно откуда взялось 0x600.

ЗЫ: Поищите другое описание тсп. Приведенное Вами, несколько сумбурное.
vesago
Статья конечно не основание. Я почитываю соответствующий RFC. В статье просто некоторые ньюансы рассмотрены. В частности сказано, что как и вашем коде процедура расчета чексум общая для всех частей IP пакета. Но вот у меня не получается хоть тресни. Не могу понять почему у вас работает и в фриварных стеках. Наверное забью я на эту общую чексум и буду пользовать для каждо части свою процедуру. По крайней мере так сходится.
Rst7
Шепну по секрету, что очень уж долгая песня расчет CRC в 32-битном варианте - много загрузок, много регистров требуется... Поэтому лично я набрался наглости сделать так:
Код
unsigned int rxcrc;

#pragma optimize=no_inline
void subrxcrc(unsigned int i)
{
i=rxcrc-i;
if (_CARRY) i--;
rxcrc=i;
}


Имеется в виду добавление одного слова к CRC.

На код стало куда более приятно смотреть...
vesago
Недурственная идея. А сам алгоритм у вас как вышерассмотренный? Используете тоже одну функцию для всех частей IP пакета?
Rst7
Цитата(vesago @ Oct 11 2006, 11:28) *
Недурственная идея. А сам алгоритм у вас как вышерассмотренный? Используете тоже одну функцию для всех частей IP пакета?


Ох... Там через одно место для экономии... Так что прицепляю исходники моего TCP/IP стека через SLIP Нажмите для просмотра прикрепленного файла... Почитайте, может чего полезного извлечете... Есть там пара фишек типа переключения контекстов через setjmp/longjmp и т.д. Сделано под IAR.Нажмите для просмотра прикрепленного файла
vesago
Спасибо. Очень интересный код - вроде маленькой оси. Оказывается в яре есть функция смены порядка байтов __reverse. А я искал типа htons.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.