С Новым годом! Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ARM, Cortex, STM32
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.83/18: Рейтинг темы: голосов - 18, средняя оценка - 4.83
38 / 31 / 9
Регистрация: 29.03.2019
Сообщений: 345
1

Подсчет контрольной суммы заголовка IP пакета

31.10.2019, 15:09. Показов 3676. Ответов 13

Author24 — интернет-сервис помощи студентам
Здравствуйте, уважаемые форумчане.

На канале narodstream автор производит подсчет контрольной суммы пришедшего IP пакета следующей функцией.
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*********************************************************************************************
*в функции checksum рассчитывается только заголовок пакета
*заголовок разбивается на 16 битные величины
*и все эти кусочки складываются  
*Перед использованием функции checksum  нужно обнулить контрольную сумму в заголовке пакета
**********************************************************************************************/
uint16_t checksum(uint8_t *ptr, uint16_t len)
{
    uint32_t sum = 0; //сумма в 16 бит может не уместиться поэтому создаем переменную для 32 бит
    
    while(len > 0) // пока длина заголовка пакета больше нуля - складываем 
    {
        sum += (uint16_t) (((uint32_t)*ptr<<8) |*(ptr+1));//складываем кусочки заголовка по 16 бит
        ptr+=2; //переходим по указателю еще на 16 бит
        len-=2; //длину соответственно уменьшаем на 2 байта
    }
    if (len) sum+=((uint32_t)*ptr)<<8; // если длинна уменьшилась не до нуля, то к полученной сумме прибавляем еще 
                                                // старший байт. т.е. старший байт становится по адресу ptr, а младший освобождается
    while(sum>>16) sum = (uint16_t)sum+(sum>>16); //если бы старшая величина была бы равна 0 то мы вышли бы из этого цикла, в противном случае в старшей части что-то осталось и поэтому снова производим операцию сложения
    return ~((((((uint16_t)sum)>>8)&0xff)|((((uint16_t)sum)<<8)&0xff00))); //здесь мы преобразовали к виду big endian и сделали побитовую инверсию
}
Функция, конечно, не простая для меня. Не пойму вот эту строку
C
1
if (len) sum+=((uint32_t)*ptr)<<8;
Как мы в нее попадем, если мы в цикле выше обнулим все до нуля? И для чего мы ее используем?
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
31.10.2019, 15:09
Ответы с готовыми решениями:

Структура пакета и расчет контрольной суммы для RS485
Стоит задача реализовать структуру (скелет) пакета для обмена по RS485. Master-орм выступает...

Ошибка контрольной суммы передаваемого пакета при выставлении Parity Odd
Всем привет! Микроконтроллер (Подчиненный) общается с компьютером (Мастер) по определённому...

Расчет контрольной суммы ip заголовка
Всем доброго времени суток. Стоит задача рассчитать контрольную сумму ip заголовка. Пробовал...

Проблема рассчета контрольной суммы TCP-заголовка
Здравствуйте! Активно занимаюсь написанием ПО для микроконтроллеров. Пару раз писал к вам на...

Подсчёт контрольной суммы
Приветствую! Необходимо подсчитать 32-битную сумму для файла checksum = word1 + word2 + ... +...

13
Эксперт .NET
11120 / 7037 / 1577
Регистрация: 25.05.2015
Сообщений: 21,292
Записей в блоге: 14
31.10.2019, 15:26 2
Вы уверены, что это правильный алгоритм? Проверенный? Приведённый в руководствах?
1
38 / 31 / 9
Регистрация: 29.03.2019
Сообщений: 345
31.10.2019, 15:41  [ТС] 3
Rius, Да, я в нем уверен. Потому, что контрольную сумму он считает правильно. Проверял для IP пакета.
И проверил для UDP пакета. вот с такой вот доработкой от автора.
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
uint16_t checksum(uint8_t *ptr, uint16_t len, uint8_t type)
{
    uint32_t sum = 0;
    
    if(type == 1) // это для UDP
    {
        sum+=IP_UDP;
        sum+=len-8;
    }   
                            
    while(len > 0)
    {
        sum += (uint16_t) (((uint32_t)*ptr<<8) |*(ptr+1));
        ptr+=2; //переходим еще на 16 бит 
        len-=2; //
    }
    if (len) sum+=((uint32_t)*ptr)<<8;
    while(sum>>16) sum = (uint16_t)sum+(sum>>16); 
    return ~be16toword((uint16_t)sum); //сдесь мы переобразовали к виду big endian и сделали побитовую инверсию
}
Расчет согласно такому руководству:
Заголовок пакета делится на 16 битные кадры. Затем они складываются. Затем полученная сумма переводится в формат биг эндиан и потом она инвертируется. Если не умещается в 16ти битную величину, тогда сумма делится на старшее полуслово и младшее и снова складывается и так пока не поместится.
Нюанс.: если заголовок получился из нечетного числа байт, тогда последний байт выравниваем нулем. Тогда следующий байт становится старшим, а в младший пишем все нули.
И еще нужно сказать, что контрольная сумма в заголовке должна быть обнулена перед расчетом контрольной суммы
0
874 / 535 / 175
Регистрация: 30.07.2015
Сообщений: 1,739
31.10.2019, 15:44 4
Лучший ответ Сообщение было отмечено northcitizen как решение

Решение

northcitizen,
C
1
while(len > 0)
в данном случае эквивалентно
C
1
while(len)
так что у вас никогда программа не попадет сюда:
C
1
 if (len) sum+=((uint32_t)*ptr)<<8;
1
38 / 31 / 9
Регистрация: 29.03.2019
Сообщений: 345
31.10.2019, 16:27  [ТС] 5
_SayHello, Спасибо за помощь

Добавлено через 39 минут
Тогда нужно так
C
1
2
3
4
5
6
while(len > 1)
    {
        sum += (uint16_t) (((uint32_t)*ptr<<8) |*(ptr+1));
        ptr+=2; //переходим еще на 16 бит 
        len-=2; //
    }
и тогад мы проверим заголовок на четность и если он будет нечетным
C
1
if (len) sum+=((uint32_t)*ptr)<<8;
Как сказал автор: "Если байт действительно остался, то сдвинем его влево, тем самым заодно освободим правую часть для дополнения нулями до чётности "
0
Эксперт .NET
11120 / 7037 / 1577
Регистрация: 25.05.2015
Сообщений: 21,292
Записей в блоге: 14
31.10.2019, 16:34 6
Цитата Сообщение от northcitizen Посмотреть сообщение
Да, я в нем уверен.
Только вот в коде видно обратное - недостижимый код. Прописано то, что не работает. Значит, код может содержать и другие ошибки.

Цитата Сообщение от northcitizen Посмотреть сообщение
Тогда нужно так
Нужно написать тест, чтоб сравнить результаты этого метода с контрольными суммами, полученными другими способами.
1
38 / 31 / 9
Регистрация: 29.03.2019
Сообщений: 345
31.10.2019, 16:51  [ТС] 7
Rius, согласен. глупо получилось...
0
912 / 672 / 134
Регистрация: 01.03.2010
Сообщений: 1,273
31.10.2019, 20:08 8
Цитата Сообщение от northcitizen Посмотреть сообщение
Rius, согласен. глупо получилось...
Этот человек провел огромную работу. Хотя частенько путает в уроках а потом исправляет. Думаю, он привлек большое внимание людей, начинающих изучать МК, хотя и не позиционирует себя как гуру. Вот и вы разбираете МК в том числе и по его урокам. Чего то не понимаете и спрашиваете здесь. Так это отлично. Когда нибудь, может быть, и в более низкий уровень погрузитесь.
1
87 / 86 / 4
Регистрация: 20.11.2016
Сообщений: 262
18.04.2021, 22:32 9
Тоже пришлось столкнуться с этим кодом при изучении уроков на этом сайте. Много там неоптимального кода...
Вот например можно поменять местами операции с указателями. Вместо
C
1
sum += (uint16_t) (((uint32_t)*ptr<<8) |*(ptr+1));
пишем
C
1
sum += (uint16_t) ((uint32_t)*ptr |*(ptr+1) <<8);
это нам позволит избавиться от перестановки байтов при возврате из функции
вместо
C
1
 return ~be16toword((uint16_t)sum);
будет
C
1
return ~((uint16_t)sum);
Добавлено через 17 минут
А есть и более удобный вариант подсчета контрольной суммы который оперирует сразу с шестнадцатиразрядными данными, а не с байтами). Подсмотрел на другом сайте.
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
uint16_t ip_check_sum(uint16_t *buf, uint8_t len)
{
    uint32_t sum = 0;
    // Рассчитываем сумму word'ов блока
    while (len>1)
    {
        sum += *buf;
        buf ++;
        len -= 2;
    }
 
    if (len)            // если остался нечетный байт
        sum += (uint8_t)*buf;
 
    // Складываем старший и младший word суммы
    // пока не получим число, влезающее в word
    while (sum >> 16)
        sum = (sum & 0xffff) + (sum >> 16);
 
    //Берём дополнение до единицы
    return ~((uint16_t)sum);
}
0
874 / 535 / 175
Регистрация: 30.07.2015
Сообщений: 1,739
19.04.2021, 10:58 10
Radikal_78, для перестановки байтов есть ARMa инструкция в файле core_cmInstr.h
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/** \brief  Reverse byte order (16 bit)
 
    This function reverses the byte order in two unsigned short values.
 
    \param [in]    value  Value to reverse
    \return               Reversed value
 */
__attribute__( ( always_inline ) ) static __INLINE uint32_t __REV16(uint32_t value)
{
  uint32_t result;
 
  __ASM volatile ("rev16 %0, %1" : "=r" (result) : "r" (value) );
  return(result);
}
1
87 / 86 / 4
Регистрация: 20.11.2016
Сообщений: 262
19.04.2021, 21:06 11
_SayHello, спасибо вам большое))) с ассемблером знаком конечно, но совершенно забыл о такой возможности((((
0
1978 / 1276 / 131
Регистрация: 04.01.2010
Сообщений: 4,607
24.04.2021, 22:26 12
Цитата Сообщение от Radikal_78 Посмотреть сообщение
но совершенно забыл о такой возможности((((
не переживайте, gcc за вас все это давно учитывает. на 99% уверен, что ваши попытки оптимизировать (даже асмом) код бесполезны.
0
874 / 535 / 175
Регистрация: 30.07.2015
Сообщений: 1,739
27.04.2021, 08:42 13
Voland_, вообще можно аппаратный модуль подсчета CRC прикрутить, будет еще оптимальнее. Правда не то чтобы у IP пакета много данныз для расчета контрольной суммы
0
1978 / 1276 / 131
Регистрация: 04.01.2010
Сообщений: 4,607
27.04.2021, 11:27 14
Цитата Сообщение от _SayHello Посмотреть сообщение
можно аппаратный модуль подсчета CRC прикрутить
да, lwIP так и делает
0
27.04.2021, 11:27
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
27.04.2021, 11:27
Помогаю со студенческими работами здесь

Подсчёт контрольной суммы
Помогите перевести. На СИ это выглядит так: //CRC-16-CCITT, Образующий многочлен = 0x1021 int...

Подсчет контрольной суммы
С массивами, состоящими из скромных значений, работает, но вот с такими числами - нет . Правильный...

Подсчет контрольной суммы
Добрый день! Подскажите пожалуйста как можно реализовать маленькую программку. Нужно удалить файлы...

Подсчет CRC16 контрольной суммы
Ищу написанную на VB (!) программу подсчета CRC16 контрольной суммы или соответствующий API.

Подсчёт контрольной суммы файла
Форумчане,добрый вечер! такой вопрос:не могли бы вы написать примерный код(Си),благодаря которому...

Подсчет контрольной суммы в textbox
В textbox в водится число, например &quot;123456789&quot; нужно посчитать контрольную сумму этого числа по...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru