Открытие и закрытие

Предыдущая  Содержание  Следующая V*D*V

Наш драйвер может проверить интерфейс во время загрузки модуля или при загрузке ядра. Однако, до того, как интерфейс сможет передавать пакеты, ядро должно его открыть и присвоить ему адрес. Ядро открывает или закрывает интерфейс в ответ на команду ifconfig.

 

Когда ifconfig используется, чтобы присвоить интерфейсу адрес, она выполняет две задачи. Во-первых, она присваивает адрес при помощи ioctl(SIOCSIFADDR) (Socket I/O Control Set Interface Address, установка адреса интерфейса для управления сокетом ввода/вывода). Затем она устанавливает бит IFF_UP в dev->flag с помощью ioctl(SIOCSIFFLAGS) (Socket I/O Control Set Interface Flags, установка флагов интерфейса для управления сокетом ввода/вывода), чтобы включить интерфейс.

 

Что касается устройства, ioctl(SIOCSIFADDR) не делает ничего. Функция драйвера не вызывается - задача является независимой от устройства и её выполняет ядро. Однако, последняя команд (ioctl(SIOCSIFFLAGS)) вызывает метод open для данного устройства.

 

Аналогично, когда интерфейс выключается, ifconfig использует ioctl(SIOCSIFFLAGS) для очистки IFF_UP и вызывается метод stop.

 

Оба метода устройства возвращают 0 в случае успеха и обычное отрицательное значение в случае ошибки.

 

Как же касается собственно кода, драйвер должен выполнять многие из тех же задач, что делают символьные и блочные драйверы. open запрашивает все необходимые системные ресурсы, необходимые и приказывает интерфейсу подняться; stop выключает интерфейс и освобождает системные ресурсы. Однако, сетевые драйверы во время открытия должны выполнять некоторые дополнительные действия.

 

Во-первых, до того, как интерфейс сможет общаться с внешним миром, из аппаратного устройства в dev->dev_addr должен быть скопирован аппаратный (MAC) адрес. Аппаратный адрес может быть скопирован в устройство во время открытия. Программный интерфейс snull присваивает его внутри open; он просто подделывает аппаратный адрес, используя строку ASCII длиной ETH_ALEN, длины адресов Ethernet оборудования.

 

Метод open также должен запустить очередь передачи интерфейса (разрешая ему принимать пакеты для передачи), как только он готов начать передачу данных. Чтобы запустить очередь, ядро предоставляет функцию:

 

void netif_start_queue(struct net_device *dev);

 

Код open для snull выглядит следующим образом:

 

int snull_open(struct net_device *dev)

{

    /* request_region( ), request_irq( ), .... (подобно fops->open) */

 

    /*

     * Назначаем плате аппаратный адрес: используем "\0SNULx", где

     * x это 0 или 1. Первым байтом является '\0', чтобы не быть групповым

     * адресом (первый байт групповых адресов является нечётным).

     */

    memcpy(dev->dev_addr, "\0SNUL0", ETH_ALEN);

    if (dev == snull_devs[1])

        dev->dev_addr[ETH_ALEN-1]++; /* \0SNUL1 */

    netif_start_queue(dev);

    return 0;

}

 

Как вы можете видеть, в отсутствие реального оборудования, в методе open мало что можно сделать. То же самое относится и к методу stop; он просто отменяет операции open. По этой причине, функцию, реализующую stop, часто называет close или release.

 

int snull_release(struct net_device *dev)

{

    /* освобождаем порты, прерывание и остальное -- подобно fops->close */

 

    netif_stop_queue(dev); /* больше передавать не можем */

    return 0;

}

 

Функция:

 

void netif_stop_queue(struct net_device *dev);

 

является противоположностью netif_start_queue; она отмечает, что устройство больше не может передавать пакеты. Функция должна вызываться при закрытии интерфейса (в методе stop), но может также использоваться для временного прекращения передачи, как описано в следующем разделе.

Предыдущая  Содержание  Следующая