Запись драйвера для контроллера Ethernet

В этой главе описываются то, что сетевой драйвер делает, чтобы установить его интерфейсный объект, обработать I/O и выполнить его другие задачи. Следуйте за драйвером Ethernet CDC, предоставленным в http://www .opensource.apple.com/darwinsource/tarballs/apsl/AppleUSBCDCDriver-314.4.1.tar.gz для определенных примеров того, как реализовать функциональность, требуемую сетевого драйвера. В частности этот документ будет относиться к функциям в AppleUSBCDCEMData.cpp.

Обзор драйвера

Прежде, чем погрузиться в специфические особенности того, чем необходимо быть, делают для записи сетевого драйвера, может быть полезно видеть основные функции, которые необходимо переопределить. Эти описания предназначаются для давания Вам общее представление о том, что вызвано в создании очень простого сетевого драйвера.

start

start функция должна инициализировать устройство к рабочему состоянию. Это также должно создать сетевой объект и сделать его видимым к сетевому стеку как интерфейс.

stop

stop функция должна освободить что-либо выделенное в start и также выпустите сетевой объект, создаваемый в start.

enable

Как упомянуто в Подсказках относительно Перевода в рабочее состояние Сетевого драйвера UNIX, enable когда система устанавливает водительское состояние в, функция выполняется up. Эта функция также ответственна за запуск передачи аппаратных средств, и получите возможности. Это должно сообщить системе о состоянии канала аппаратных средств.

disable

disable функционируйте выпускает что-либо выделенное и останавливается, любые функции запустились в enable.

getHardwareAddress

getHardwareAddress функционируйте возвращает MAC-адрес сетевого устройства.

outputPacket

outputPacket функция отправляет пакет в аппаратные средства для передачи. Это вызовут от многократных потоков, таким образом, это должно будет быть ориентировано на многопотоковое исполнение.

Каждая из этих функций описана в большей глубине далее в этой главе.

Запуск и завершение работы

Сетевой драйвер start все время функция ответственна за установку ресурсов потребности драйвера, включен ли драйвер или отключен. Они включают объект сетевого интерфейса, цикл работы и очередь вывода, вместе с любыми определенными ресурсами потребности драйвера. Кроме того, драйвер должен сохранить свой кусок провайдера (т.е. кусок для шины, к которой это присоединено, такие как кусок IOUSBDevice). stop функционируйте инвертирует все это, выпуская кусок и избавляясь от любых ресурсов, создаваемых в start. Посмотрите драйвер в качестве примера для выборок этих двух функций.

start функция обычно является не местом для драйвера, чтобы выделить его передачу и получить буферы и другие такие ресурсы во время выполнения, которые необходимы только, в то время как драйвер включен и обрабатывающий сетевой трафик. Созданием и избавлением от этих ресурсов управляют enable и disable функции, описанные во Включении и Отключении Драйвера.

Открытие куска провайдера

Вы вызываете start функция с отдельным аргументом, куском устройства, к которому подключен Ваш контроллер Ethernet. Драйвер должен сделать три вещи с куском: проверьте, что это имеет надлежащий класс, сохраните ссылку на него и откройте его для доступа к ее службам.

Ваш драйвер имеет две опции прежде, чем возвратиться из start функция. Если Вы закрываете кусок в конце start функция, тогда необходимо вновь открыть его в enable функция. Однако у Вас также есть опция оставить кусок открытым, так, чтобы это было готово использовать в enable функция. Рекомендуется, чтобы прежний метод использовался, но потому что сетевой драйвер редко «побеждается», любой метод приемлем. Пример кода использует последний метод.

Установка Выходной Организации очередей

IONetworkController, суперкласс всех сетевых драйверов, определяет outputPacket функция для передачи пакетов. Эта функция обычно вызывается косвенно сетевым интерфейсом посредством стандартной организации очередей сетевой семьи механизма, определенного IOOutputQueue и его подклассами. Драйвер может принять решение вызвать его непосредственно сетевым интерфейсом, однако, и реализовать его собственный внутренний механизм организации очередей.

Водительская очередь вывода создается createOutputQueue функция. Суперкласс сетевого драйвера, IONetworkController, вызывает эту функцию автоматически на запуск. Драйвер должен переопределить эту функцию, чтобы создать экземпляр подкласса IOOutputQueue, подходящего для драйвера или не переопределить его вообще, если драйвер выполняет свою собственную организацию очередей — когда сетевой интерфейс передаст исходящие пакеты непосредственно драйверу.

Самым простым подклассом IOOuputQueue для использования является IOGatedOutputQueue. Этот класс пакеты очередей с помощью блокировки и исключает их из очереди по одному использование логического элемента команды на водительском цикле работы. Это вызывает outputPacket один раз для каждого пакета, разбиваясь mbuf_t пакетные цепочки так, чтобы драйвер не обрабатывал их. Используя работу цикл означает, что передача и получает операции, являются взаимоисключающими. Если Ваше сетевое оборудование имеет абсолютно отличную передачу, и получите механизмы, использование объекта IOGatedOutputQueue может не быть самой эффективной опцией. Несмотря на это, это делает перевод в рабочее состояние драйвера довольно простым, поскольку Вы не должны волноваться о блокировке при установлении управления самих аппаратных средств.

Если Ваше сетевое оборудование поддерживает многопоточный доступ, как это делает, когда передача и получает механизмы, отличны, можно хотеть использовать IOBasicOutputQueue вместо этого. Этот класс фактически суперкласс IOGatedOutputQueue, и это определяет механизм блокировки тот IOGatedOutputQueue использование. Для того, чтобы исключить из очереди, однако, это согласовывает многократные потоки организации очередей так, чтобы только единственный поток во время исключил пакеты из очереди и вызвал водительское outputPacket функция. Этот подкласс очереди также разбивается mbuf_t пакетные цепочки для драйвера. Поскольку исключение из очереди не синхронизируется с циклом работы, однако, и передача и прием могут произойти одновременно.

Если драйвер выполняет организацию очередей внутренне, это не переопределяет createOutputQueue, и это реализует свой собственный механизм организации очередей. Если Вы портируете драйвер, уже выполняющий его собственную выходную блокировку, например, то Вы, вероятно, выберете эту опцию. В этом случае, когда сетевой интерфейс должен передать пакеты, он вызывает водительское outputPacket функционируйте непосредственно. Драйвер тогда ответственен за всю блокировку его внутренней очереди и связанных данных для обработки условий останова, и далее для обработки mbuf_t пакетные цепочки. Классы очереди вывода гарантируют, что единственный пакет за один раз передается outputPacket; дело обстоит не так, когда драйвер воздерживается от использования объекта очереди вывода.

Другая опция, которую имеет драйвер, состоит в том, чтобы создать свой собственный подкласс IOOutputQueue. См. документацию ссылки класса и исходный код для получения дополнительной информации.

Установка Сетевого интерфейса

Как с любым драйвером, сетевой драйвер ответственен за создание его куска. Сетевой кусок является экземпляром подкласса IONetworkInterface. Каждый тип сетевого контроллера имеет соответствующий подкласс IONetworkInterface; IOEthernetController, например, использует IOEthernetInterface. Создание сетевого интерфейса реализовано водительским суперклассом; весь драйвер должен сделать, вызвать attachInterface функция и реализация несколько вспомогательных функций. Если драйвер включает пользовательский подкласс класса сетевого интерфейса, он может переопределить createInterface создать экземпляр пользовательского подкласса, а не класса по умолчанию.

attachInterface функция берет два параметра: указатель на объект сетевого интерфейса, который заполнен функцией и дополнительным “регистром с сетевыми стеками” флаг. Этот флаг true по умолчанию, означая, что интерфейсный объект будет зарегистрирован в DLIL, что водительское enable функция может быть вызвана во время запуска и что драйвер может получить запросы для передачи пакетов прежде attachInterface возвраты (и прежде start завершается). Если Ваш драйвер должен выполнить дополнительную инициализацию, можно передать false задержать регистрацию в сетевых стеках. Если Вы делаете это, Ваш драйвер должен вызвать интерфейс registerService функционируйте, когда это станет готовым для обработки сетевого трафика.

Поскольку сетевой интерфейс не может быть реконфигурирован после того, как он регистрирует себя в сетевом стеке BSD, он вызывает обратный вызов на драйвер от attachInterface функция. Обратный вызов configureInterface, и драйвер может реализовать его для установки максимальных размеров передачи, режимов касания фильтра и других таких настроек, как описано в справочной документации IONetworkInterface. Сетевые драйверы обычно используют эту функцию для получения их ссылок на структуры статистики, сохраняемые сетевым интерфейсом, прежде чем любой сетевой трафик прибудет. (См. Собирающуюся Статистику сети ниже для получения информации о том, как сделать это.)

Для драйверов Ethernet другая функция, связанная с установкой интерфейса, getHardwareAddress, который интерфейсный объект вызывает для регистрации Ethernet-адреса в сетевом стеке BSD. Перед вызовом attachInterface, драйвер должен определить в start функционируйте, что аппаратный адрес, и реализация getHardwareAddress обеспечить этот адрес по запросу. Другие сетевые протоколы могут потребовать подобной функции.

Определяя возможности, ограничения и режимы

Этот раздел представляет некоторые полезные функции, которые будут объяснены более полно в более поздних версиях этой книги.

Сетевой драйвер переопределяет много функций IONetworkController для распространения его возможностей и ограничений. Некоторые из этих функций, и их использование:

Включение и отключение драйвера

Когда сетевой интерфейс переведен в рабочее состояние — например, с помощью ifconfig команда — водительское enable функция вызывается. Эта функция ответственна за подготовку драйвера, чтобы передать и получить пакеты. Вот несколько операций, обычно выполняемых в enable:

disable функция должна инвертировать этот процесс, отключив то, что было включено, закрыв то, что было запущено, избавившись от ресурсов, создававшихся, и, при необходимости, закрывая кусок провайдера. Драйвер должен также сбросить аппаратные средства при отключении, для отъезда его в известном состоянии.

Вы вызываете enable и disable функции в синхронизируемом контексте через водительский суперкласс, с помощью IOCommandGate на водительском цикле работы. Эти функции предназначаются, чтобы быть переопределенными, и не непосредственно вызванными.

Открытие и закрытие куска провайдера

Оба enable и disable вызываются с куском провайдера, с которого был первоначально запущен драйвер. enable функция ответственна за вызов open на куске, возвращая результат отказа, если это не может открыть кусок. Точно так же disable должен вызвать close на куске. Поскольку код сетевого драйвера может работать в многократных потоках, однако, драйвер должен реализовать взаимное исключение. Блокировка должна гарантировать что enable функции позволяют работать только один раз за один раз, и что disable функция может работать только за enable функция. Демонстрационный драйвер использует Логическую переменную, fNetifEnabled, как блокировка.

Создание и уничтожение ресурсов

Для сохранения ресурсов ядра драйвер никогда не должен использовать больше системной памяти, чем необходимый. Это означает, что драйвер должен задержать ресурсы создания, пока они не фактически необходимы, как тогда, когда драйвер становится активным, и должен избавиться от тех ресурсов, когда это становится неактивным. Такие ресурсы обычно включают любую специфичную для аппаратных средств передачу и получают буферы, BSD mbuf_t структуры раньше передавали пакеты вверх и вниз, объекты курсора памяти раньше управляли, рассеиваются/собирают списки на основе mbuf_t структуры и любые источники событий необходимы для работы.

Специфичные для аппаратных средств ресурсы обязательно выходят за рамки этого документа. Независимо от того, что специфичные для аппаратных средств ресурсы, однако, они будут обычно включать содержащий получить буфер mbuf_t структуры. Ваш драйвер может использовать свой объект сетевого интерфейса выделить и освободить эти структуры через allocatePacket и freePacket функции, определяемые IONetworkController.

Курсоры памяти, представленные группой IOMBufMemoryCursor классов, управляют переводом между mbuf_t структуры и рассеиваются/собирают списки, используемые аппаратными средствами. Определенные классы доступны, чтобы обработать данные в обратном порядке байтов, прямом порядке байтов или собственном CPU порядке байтов, и обработать данные, используемые с механизмами DBDMA. Ваш драйвер будет обычно создавать один или несколько курсоров памяти, в зависимости от того, является ли это единственным - или многопоточным и получает ли передача и буферы, используемые аппаратными средствами, подобны или отличаются.

Запуск и остановка I/O

Запустить I/O, enable функция должна включить прерывание и источники событий таймера и затем включить любые специфичные для аппаратных средств прерывания. После этого это должно запустить очередь вывода (если это имеет один), использование IOOutputQueue setCapacity и start функции. Наконец, это должно запустить любые двигатели I/O на аппаратных средствах.

disable функционируйте останавливает I/O путем грубого инвертирования этого процесса. Это должно отключить специфичные для аппаратных средств прерывания, отключить источник события прерывания и отменить любой незаконченный тайм-аут. Это должно тогда остановить механизмы I/O и сбросить аппаратные средства при необходимости. Затем это должно остановить и сбросить очередь вывода путем вызова stop функция, обнуляя ее способность с setCapacity, и вызов flush.

Выполнение I/O

Все, что было покрыто до сих пор, является по существу поддержкой в реальной цели сетевого драйвера: отправить и получить пакеты через сетевой контроллер. Сетевая семья указывает средние значения для драйвера, чтобы получить выходной запрос от объекта сетевого интерфейса и вручить полученным пакетам до него, а также определяющий структуры данных для сбора статистики. Дополнительные функции, определяемые суперклассами сетевого интерфейса и контроллера предоставляют поддержку для управления буферами пакетов, и mbuf_t средство классов курсора памяти в использовании рассеивается/собирает списки на основе тех буферов.

Передача пакетов

Точка входа сетевого драйвера для передачи outputPacket функция. Эта функция вызывается или IOOutputQueue или сетевым интерфейсом непосредственно. В зависимости от типа используемой очереди (см. Установку Выходной Организации очередей выше), эта функция может или не может быть вызвана в защищенном контексте водительского цикла работы.

Единственный параметр outputPacket mbuf_t для пакета или пакетов, которые будут переданы. Драйвер, использующий объект очереди вывода, как гарантируют, будет передан единственный пакет mbuf_t. Драйвер, делающий его собственную организацию очередей, должен быть в состоянии обработать цепочку пакетов на сингле mbuf_t указатель. mbuf_t переданный в становится свойством драйвера.

Для фактического вывода пакета или пакетов драйвер должен проверить свои специфичные для аппаратных средств ресурсы и подготовить буфер. В зависимости от состояния ресурсов драйвер, возможно, должен возвратить пакетное состояние остановленных (kIOReturnStall), как тогда, когда аппаратные буферы передачи все полны, или отброшенные (kIOReturnDropped), как тогда, когда ошибка происходит в обработке пакета. Если возвращается драйвер kIOReturnDropped, это должно также поместить mbuf_t назад в общий пул сетевого стека путем вызова суперкласса freePacket функция.

Для генерации рассеиваться/собирать списка для пакета драйвер использует IOMBufMemoryCursor, вызывая getPhysicalSegmentsWithCoalesce функция для создания списка физических пар расположения/длины для сегментов памяти mbuf_t. Как только это имеет эту информацию, драйвер может вставить его в аппаратные буферы и выпустить сигнал к аппаратному контроллеру.

После того, как пакет был передан аппаратными средствами, драйвер должен предъявить претензии в отношении своего буфера передачи и поместить mbuf_t назад в общий пул сетевого стека путем вызова суперкласса freePacket функция.

Получение пакетов

Получение пакетов обычно делается через обработчика прерываний, или возможно таймер для устройства, требующего опроса. В любом случае прием всегда обрабатывается в защищенном контексте водительского цикла работы

Для обработки входящих пакетов драйвер должен извлечь mbuf_t структура для каждого от ее аппаратных средств получает буферы и передает его до объекта сетевого интерфейса путем вызова что объект inputPacket функция. Для эффективной замены mbuf_t структура, содержащая полученный пакет, IONetworkController определяет функции copyPacket, replacePacket, и replaceOrCopyPacket, который выполняет самую эффективную работу на основе размера полученного пакета. В то время как рекомендуется использовать эти функции, драйвер в качестве примера не использует в своих интересах их.

inputPacket функция имеет дополнительный аргумент для обеспечения организации очередей многократных пакетов. Если драйвер использует входную организацию очередей, он должен вызвать сетевой интерфейс flushInputQueue функция, чтобы гарантировать, чтобы пакеты сочли свой путь сетевым стеком.

Сбор статистики сети

Сетевая семья определяет несколько структур для записи статистики сети. Если Вы хотите, чтобы Ваш драйвер сделал это, это должно получить адреса этих структур от объекта сетевого интерфейса и затем обновить соответствующие поля во время работы.

Структуры доступны от объекта сетевого интерфейса до getNetworkData функция. Эта функция берет имя соответствующей структуры сетевых данных, для которой константы определяются классами сетевого интерфейса. Константа kIONetworkStatsKey, например, указывает универсальную структуру статистики сети, содержащую поля для числа пакетов ввода и вывода среди других.

getNetworkData функционируйте возвращает объект IONetworkData, от которого можно получить адрес буфера данных с помощью getBuffer функция. Кастинг возвращенного указателя на надлежащий тип предоставляет Ваш прямой доступ драйвера к структуре сетевых данных.

Распространение и изменение режимов фильтра

Для указания, что поддерживают виды пакетной фильтрации (адресуя) драйвер она переопределяет getPacketFilters. Эта функция вызывается с указателем на битовое поле, указывающее, какие способы адресации поддерживаются, такой, как одноадресно передано, широковещательно передаются и многоадресно передаются. Водительская реализация этой функции должна установить биты для режимов, которые это поддерживает, и возвратите код успеха.

Для поддержки неразборчивых и многоадресных режимов сетевой драйвер переопределяет setPromiscuousMode, setMulticastMode, и setMulticastList функции, определяемые IONetworkController. Функции режима набора могут быть реализованы, чтобы просто установить флаг в драйвере; фактически поддержка режимов требует специфичного для аппаратных средств кода в функциях обработки I/O, конечно. setMulticastList вызывается со списком аппаратных адресов, которые драйвер должен передать к аппаратным средствам.

Распространение и изменение носителей

Когда драйвер сетевого контроллера запускает, он обычно исследует свои аппаратные средства на носители, поддерживаемые и в настоящее время активные на example10Base-T и 100Base-T для Ethernet. Драйвер может распространить эти носители путем создания экземпляра IONetworkMedium для каждого, сбора их в OSDictionary, который это делает доступным для сетевой семьи путем вызова setMediumDictionary функция, определяемая IONetworkController.

Драйвер должен также вызвать setCurrentMedium установить текущий выбранный носитель. Точно так же, когда драйвер отмечает, что сетевой канал подошел или потерял работоспособность, это должно вызвать setLinkStatus функционируйте для создания отчетов о состоянии объекту сетевого интерфейса.