Ответ 1
Контрольная сумма UDP выполняется для всей полезной нагрузки, а также для других полей в заголовке и некоторых полей из заголовка IP. Псевдозаголовок составляется из IP-заголовка, чтобы выполнить вычисление (которое выполняется над этим псевдозаголовком, UDP-заголовком и полезной нагрузкой). Причина, по которой включается псевдо-заголовок, состоит в том, чтобы перехватывать пакеты, которые были направлены на неправильный IP-адрес.
По сути, на принимающей стороне все 16-битные слова заголовков плюс область данных складываются вместе (перенос в 16 бит), и результат проверяется по 0xffff
.
С отправляющей стороны это немного сложнее. Для всех 16-битных значений выполняется одна сумма дополнения, затем берется одно дополнение (т.е. инвертирует все биты) этого значения для заполнения поля контрольной суммы (с дополнительным условием, что вычисленная нулевая контрольная сумма будет изменена на все один бит).
Одна сумма дополнения - это не просто сумма всех значений одного дополнения. Это немного сложнее.
По сути, у вас есть работающий 16-разрядный аккумулятор, начинающийся с нуля, и вы добавляете к нему каждое 16-разрядное значение. Всякий раз, когда одно из этих добавлений приводит к переносу, значение оборачивается, и вы снова добавляете его к значению. Это эффективно берет бит переноса 16-битного сложения и добавляет его к значению.
В качестве отступления, и это чистая гипотеза с моей стороны, но, вероятно, это можно было бы эффективно сделать, используя инструкцию
ADC
(добавить с переносом), а неADD
(как ни удивительно, добавить), или любые другие эквивалентные инструкции, которые были доступны на вашем процессоре в то время.Если бы не было переноса,
ADC
просто добавил бы нулевой бит из переноса. В те дни, когда это было сделано (и да, к сожалению, я такой старый), память была гораздо большим ограничением, чем скоростью, не так много в наши дни, поэтому сохранение нескольких байтов в вашем коде могло бы поднять вас до уровень полубога-императора вселенной :-)
Обратите внимание, что вам никогда не приходилось беспокоиться о переносе во второй раз (или переносе двух вместе со следующим ADC
, если вы используете этот метод, упомянутый в предыдущем абзаце), так как два самых больших 16-битных значения, при суммировании, производить (усечено из 0x1fffe
) 0xfffe
- добавление одного к этому никогда не вызовет другой перенос.
Как только вычисленная сумма одного дополнения вычислена, ее биты инвертированы и вставлены в пакет, это приведет к тому, что вычисление на принимающей стороне произведет 0xffff
, при условии отсутствия ошибок при передаче, конечно.
Стоит отметить, что полезная нагрузка всегда дополняется, чтобы обеспечить наличие целого числа 16-битных слов. Если он был дополнен, в поле длины указывается фактическая длина.
RFC768 - это спецификация, в которой это подробно описано.