ICMPv4 сообщение сформировано. В поле идентификатора установлен идентификатор нашего процесса, а порядковый номер установлен как глобальная переменная
nset
, которая затем увеличивается на 1 для следующего пакета. Текущее время сохраняется в части данных ICMP-сообщения.
Вычисление контрольной суммы ICMP
14-16
Для вычисления контрольной суммы ICMP значение поля контрольной суммы устанавливается равным 0, затем вызывается функция
in_cksum
, а результат сохраняется в поле контрольной суммы. Контрольная сумма ICMPv4 вычисляется по ICMPv4-заголовку и всем следующим за ним данным.
Отправка дейтаграммы
17
ICMP-сообщение отправлено на символьный сокет. Поскольку параметр сокета
IP_HDRINCL
не установлен, ядро составляет заголовок IPv4 и добавляет его в начало нашего буфера.
Контрольная сумма Интернета является суммой обратных кодов 16-разрядных значений. Если длина данных является нечетным числом, то для вычисления контрольной суммы к данным дописывается один нулевой байт. Перед вычислением контрольной суммы поле контрольной суммы должно быть установлено в 0. Такой алгоритм применяется для вычисления контрольных сумм IPv4, ICMPv4, IGMPv4, ICMPv6, UDP и TCP. В RFC 1071 [12] содержится дополнительная информация и несколько числовых примеров. В разделе 8.7 книги [128] более подробно рассказывается об этом алгоритме, а также приводится более эффективная его реализация. В нашем случае контрольную сумму вычисляет функция
in_cksum
, приведенная в листинге 28.11.
Листинг 28.11. Функция in_cksum: вычисление контрольной суммы Интернета
//libfree/in_cksum.c
1 uint16_t
2 in_cksum(uint16_t *addr, int len)
3 {
4 int nleft = len;
5 uint32_t sum = 0;
6 uint16_t *w = addr;
7 uint16_t answer = 0;
8 /*
9 * Наш алгоритм прост: к 32-разрядному аккумулятору sum мы добавляем
10 * 16-разрядные слова, а затем записываем все биты переноса из старших
22 /* перемещение битов переноса из старших 16 разрядов в младшие */
23 sum = (sum >> 16) + (sum & 0xffff); /* добавление старших 16 к младшим */
24 sum += (sum >> 16); /* добавление переноса */
25 answer = ~sum; /* обрезаем по 16 разрядам */
26 return(answer);
27 }
Алгоритм вычисления контрольной суммы Интернета
1-27
Первый цикл
while
вычисляет сумму всех 16-битовых значений. Если длина нечетная, то к сумме добавляется конечный байт. Алгоритм, приведенный в листинге 28.11, является простым алгоритмом, подходящим для программы
ping
, но неудовлетворительным для больших объемов вычислений контрольных сумм, производимых ядром.