Сегодня день рождения первого ethernet драйвера для системы Xameleon.
Эмулятор Microsoft Virtual PC поддерживает сетевую карту DEC21140. Соответственно, выбирать было не из чего. Спецификация на чип 21140 нашлась довольно быстро. Приблизительно через день, Хамелеон уже умел показывать на экране заголовки принятых широковещательных Ethernеt пакетов. Но как принять ethernet пакеты, посланные на определённый МАС адрес? И какой МАС адрес у виртуальной сетевой карты? В качестве временного решения виделась установка битов "Receive All" и "Promiscuous Mode" для приёма любых Ethernet пакетов, что гуляют по локальной сети. Что неприятно удивило, ожидаемого эффекта это не дало. По прежнему принимались исключительно широковещательные Ethernet пакеты. Уж не знаю кого в этом винить, спецификацию на сетевую карту или "MS Virtual PC".
Отчаявшись, я решил заглянуть в код драйвера Tulip, котрый идёт в составе загрузчика grub (с патчем os). Код GNU-того драйвера меня немного ошарашил - оказывается 21140 соместимых чипов великое множество и каждый производитель считал своим долгом что-либо изменить.
Оказывается, МАС адрес необходимо вычитывать из ППЗУ карты и для этого используется интерфейс I2C. Покопавшись в интернете на предмет спецификации на I2C, обнаружил что написание универсального сервиса для этого интерфейса может занять несколько дней. Тогда было решено придумать "левый" MAC и указать его в качестве адреса виртуальной карты. Поскольку этот адрес будет выводится в лог наряду с адресами других карт, то он должен "бросаться в глаза". Для этого был выбран адрес 00-03-44-44-44-44.
В спецификации сказано, что установка МАС адреса аналогична посылке пакета в сеть. Единственное отличие в том, что для конфигурационного пакета необходимо установить бит SetupPacket в дескрипторе передающих буферов. Похоже, это было самое время, чтобы попробовать послать пакет. К счастью, алгоритм посылки пакета во много похож на процесс приёма. На исход второго дня появилась первая версия драйвера, которая умела принимать и передавать Ethernet пакеты. Но как его тестировать?
Несколько лет назад я разбирался с тем, как работает TCP/IP стек. Все началось с класса, написанного моим другом для работы с COM портом. В то время мы использовали MS Visual Studio 6. В то время мы много работали с PPP поверх порта RS232. У меня возникла идея сделать разбор PPP протокола для будущего TCP/IP стека. Я понимал, что достучаться к портам сетевой карты из Windows NT невозможно, а браться за низкоуровневый перехват пакетов средствами SDK - не хотелось. Во первых, это нетривиальная задача, а во вторых, впоследствии всё равно пришлось бы переделывать это код для будущей системы. Используя PPP, можно было дописывать протоколы в соответствии с моделью OSI.
Результатом стало поднятие Windows RAS сервера и соединение портов COM1 и COM2 кабелем. Если ты пытался соединить Windows NT и Linux посредством RS232, то должен вспомнить ту ненормативную лексику, которая прозвучала из твоих уст, когда ты узнал что Windows RAS протокол имеет некоторое расширение. А именно - когда Windows используется в качестве RAS сервера, то перед началом обмена HDLC пакетами (HDLC пакет это пакет, в который обёрнуты PPP фреймы), RAS сервер должен получить строку CLIENT, на которую он отвечает CLIENTSERVER. Соответственно, не получив CLIENT, RAS сервер ничего не посылает в ответ, а по истечении таймаута "бросает трубу". Тем не менее, разобравшись с этой "фичей", мне удалось синхронизировать HDLC фреймы и получить PPP пакет. Дальше был разбор PPP пакетов и вложенных протоколов. Затем слой оперирующий с IP протоколом, затем парсер TCP и конечный автомат для сокетов. В результате получился исполняемый файл, который умел коннектиться к Windows RAS серверу, при этом получал IP адрес. Также эта программа умела отвечать на ping и, самое главное, умела коннектится к WEB серверу, посылать запрос GET и выводит полученную информацию в стандартный поток вывода.
Впрочем, я отвлёкся - доморощенный TCP/IP стек дело далёких дней. Но его исходный код бережно хранился на флешке. Глупо было бы упустить возможность с помощью этого стека потестировать драйвер сетевой карты. Тут дело начало развиваться быстрее.
Поскольку источников Ethernet фреймов может быть много (несколько сетевых карты или другое оборудование), то имеет смысл выделить отдельный программный поток (thread) для приёма любых Ethernet фреймов. При этом, TCP/IP стек и драйвер сетевой карты могут находиться как одном адресном пространстве, так и в разных. С небольшими правками, старые классы переписывались под Xameleon. IP стек также был реализован в виде программного потока. Попутно обнаружилось, что в случае использования Ethernet транспорта, IP протокол опирается на ещё один протокол - ARP.
В Сети нередко проскакивает информация о методе взлома компьютерных сетей, который называется ARP Poisoning. Поскольку мне предстояло реализовать ARP протокол, то показалось интересным заранее предусмотреть такую атаку и постараться защититься от ней. Насколько это удалось, покажет время.
На момент написания этого поста, сетевая подсистема Хамелеона пока даже не дошла до уровня программы, которая умела коннектиться к RAS серверу. Это печально, но не смертельно. Эх... Недельки бы две отпуска и у Хамелеона мог бы появиться свой TCP/IP стек.
В текущем состоянии драйвер DEC21140 представляет из себя модуль для Хамелеона, включающий в себя собственно драйвер и фрагменты оригинального TCP/IP стека. Это модуль умеет парсить и показывать на второй консоли некоторые протоколы из семейства TCP/IP. Помимо этого он умеет отвечать на пинг на адрес 192.168.1.7 и умеет рутить все пакеты, не попадающие в сеть 192.168.1.0 на адрес 192.168.1.1. Что приятно удивило, так это то, что модуль выдержал линуксовый ping c ключом -f имея минимальную потерю пакетов и одновременно с этим стабильно отвечал на ping из Windows.
Но есть и плохие новости. Microsoft Virtual PC не так широко распространён, как WMWare. Я раздобыл спецификацию на чип Am79C970A, который эмулируется WMWare, но понял, что у меня пропал интерес к написанию драйверов сетевых карт. Помимо этого, виртуальная сетевая карта, которая используется в WMWare, содержит больше регистров и сложнее в программировании. Конечно, можно было бы посвятить неделю жизни, на разработку ещё одного драйвера, но у меня нет WMWare.
Алексей Мандрыкин
27 сентября 2007 года