The OpenNET Project / Index page

[ новости /+++ | форум | wiki | теги | ]

Каталог документации / Раздел "Сети, протоколы, сервисы" / Оглавление документа

previous up down next index index
Previous: 7.1 Winsock (для UNIX, Windows-95 и -NT)    UP: 7 Программирование для сетей (новые идеи, принципы и возможности)
Down: 8 Заключение
    Next: 8 Заключение

7.2 Сетевые драйверы
Семенов Ю.А. (ГНЦ ИТЭФ)

Читатели, знакомые с телекоммуникационными протоколами, могут заинтересоваться тем, как писать прикладные программы для работы с пакетами. Прикладная программа взаимодействует с драйвером сетевого интерфейса. Ethernet-интерфейс, как и всякий другой, содержит несколько статусных управляющих регистров (CSR) и один или несколько регистров данных. Запись (чтение) в эти регистры выполняется в IBM/PC с помощью команд IN (OUT). Каждому регистру ставится в соответствие определенный номер порта. Блок номеров портов задается с помощью переключателей на интерфейсе или в процессе постановки пакетного драйвера. В последнем случае в AUTOEXEC-файле должна присутствовать строка, например (для DOS):

NE2000 0x60 0x5 0x300, (если ваша ЭВМ снабжена интерфейсом типа NE2000).

Здесь предполагается, что интерфейс будет использовать номер прерывания 0x60, аппаратное прерывание 0x5 и блок портов, начиная с шестнадцатеричного адреса 0x300 (io_addr). Следует иметь в виду, что разные интерфейсы могут иметь разное число CSR-регистров и отличные от приведенных ниже функции (NE2100). Интерфейс характеризуется тремя целыми числами: класс (8 бит), тип (16 бит) и номер. Класс говорит о том, для какой из сетевых сред предназначен данный прибор (PPP, DIX Ethernet, IEEE 802.3, IEEE 802.5, Pronet-10, Appletalk и т.д.). Тип описывает конкретную реализацию интерфейса (NE2000, NI5210, 3C501 и т.д.). Тип 0xffff соответствует всем интерфейсам данного класса. В случае, когда ЭВМ оснащена более чем одним интерфейсом идентичного типа, для их идентификации используется номер. На рис. 7.2.1 показана структура управляющего (CSR) регистра сетевого интерфейса. В таблице 7.2.1 приведен перечень основных классов с примерами определенных типов интерфейсов.

Рис. 7.2.1.А Структура CSR-регистра интерфейса (CSR0)

Init

инициализация (initialize);

Strt

старт;

Stop

стоп;

Tdnd

запрос передачи (transmit demand);

Txon

включение передачи;

Rxon

включение приема;

Inea

разрешение прерываний (interrupt enable);

Intr

прерывание;

Idon

инициализация выполнена (стирание записью 1);

Tint

прерывание при передаче (стирание записью 1);

Rint

прерывание при чтении (стирание записью 1);

Merr

ошибка при тайм-ауте на шине (стирание записью 1);

Miss

нет буфера для приема (стирание записью 1);

Cerr

ошибка из-за столкновения (стирание записью 1);

Labl

тайм-аут при передаче (стирание записью 1);

Err

ошибка типа Babl, Cerr, Miss, Merr (только для чтения).

CSR1 (доступ разрешен при CSR0[stop] = 1)

Рис. 7.2.1.Б. CSR1

CSR2 (доступ разрешен при CSR0[stop] = 1)

Рис. 7.2.1В. CSR2

Bcon

0 = <0:7> перестановка байтов адресов

Acon

0 = ale, 1 = /as

Bswp

0 = /bm1, bm0, /hold;

csr3 (доступ разрешен при CSR0[stop] = 1)

Рис. 7.2.1.Г. CSR3

Таблица 7.2.1.

Сетевая среда

Класс

Фирма, интерфейс

Тип интерфейса

dec/intel/Xerox

1

3com 3C500/3C501

1

"Bluebook" ethernet

3com 3C505

2

Interlan NI5010

3

Micom-Interlan NP600

6

Ungermann-bass PC-nic

8

Univation NC-516

9

TRW PC-2000

10

Interlan NI5210

11

3com 3C503

12

3com 3C523

13

Western digital WD8003

14

Spider systems S4

15

Torus frame level

16

10net communications

17

Gateway PC-bus

18

Gateway at-bus

19

Gateway MCA-bus

20

IMC PCnic

21

1

IMC PCnic II

22

Micromatic research

25

Clarkson "multiplexor"

26

D-link 16-bit

28

D-link ps/2

29

Research machines 16

31

Research machines MCA

32

Interlan NI9210

34

Interlan NI6510

35

Novell NE2000

36

Allied telesis pc/xt/at

38

Allied telesis NEC PC-98

39

Ungermann-bass NIC/PS2

41

Tiara lancard/E AT

42

Tiara Lancard/E MC

43

Tiara Lancard/E TP

44

AT&T Starlan NAU

47

AT&T Starlan-10 NAU

48

AT&T Ethernet NAU

49

Pronet-10

2

Proteon P1300

1

Proteon P1800

2

IEEE 802.5/pronet-4
IBM Token Ring интерфейс

3

Proteon P1340

2

Proteon P1344

3

Gateway PC-bus

4

Gateway AT-bus

5

Gateway MCA-bus

6

Omninet

4

 

 

Appletalk

5

 

 

Последовательный интерфейс

6

Clarkson 8250-slip

1

Clarkson "multiplexor"

2

Starlan

7

 

 

Arcnet

8

Datapoint RIM

1

AX.25

9

 

 

KISS

10

 

 

IEEE 802.3 w/802.2 HDRS

11

 

 

FDDI W/802.2 HDRS

12

 

 

Internet X.25

13

Western Digital

1

N.T. Lanstar (encap. dix)

14

NT Lanstar/8

1

NT Lanstar/mc

2

SLFP

15

 

 

Netrom

16

 

 

Nclass

17

 

 

Любой пакетный драйвер имеет блок исходных данных (MS-DOS), напр.:

EADDR_LEN

equ 6

 

; длина физического адреса

init_block

struc

 

 

init_mode

dw

0

 

init_addr

db

eaddr_len dup(?)

; ethernet-адрес

init_filter

db

8 dup(0)

; Логический адресный фильтр (multicast filter).

init_receive

dw

?,?

; Указатель входного кольцевого буфера

init_transmit

dw

?,?

; Указатель выходного кольцевого буфера.

init_block

ends

 

 

Структура переменных init_mode (смещение = 0) имеет вид

Рис. 7.2.2. Структура переменных init_mode

Drx

запрет приема;

Dtx

запрет передачи;

Loop

цикл;

Dtcr

запрет передачи crc;

Coll

столкновение;

Drty

запрет повторов;

Intl

внутренний цикл;

Prom

режим приема всех пакетов (promiscuous mode).

Кольцевой входной буфер имеет следующую структуру:

rcv_msg_dscp

struc

rd_addr

dw ?

; Младшая часть адреса входного буфера

rd_stat

dw ?

; Статусная часть + старшая часть адреса

rd_bcnt

dw ?

; Размер буфера в байтах

rd_mcnt

dw ?

; Длина сообщения в байтах

rcv_msg_dscp

ends

Структура переменных rd_stat имеет вид

Рис. 7.2.3. Структура переменных rd_stat

Enp

конец пакета;

Stp

начало пакета;

Buff

ошибка в буфере;

CRC

CRC-ошибка;

Oflo

переполнение буфера;

Fram

ошибка при записи в буфер;

Err

наличие ошибки;

Own

0 = полное заполнение.

Выходной буфер имеет сходную структуру.

Я не буду описывать здесь то, как следует писать системные драйверы (Исчерпывающую информацию по написанию таких драйверов читатель может найти в книге "Написание драйверов для MS-DOS" Р.Лея и "Уэйт Груп", Москва "Мир", 1995), тем более что существует достаточное их количество в депозитариях общего доступа (Например, анонимное FTP по адресам ftp.funet.fi, ftp.switch.ch или oak.oakland.edu, депозитарий SimTel ). Приведенное выше описание регистров интерфейса не является единственно возможным (см. также руководство по сетевому контроллеру 8390 и файл NE2.ASM из ссылки ftp.funet.fi. Структура драйверов варьируется для разных операционных систем. Для системных программистов полезно иметь возможность настраивать драйвер или непосредственно интерфейс на определенный режим, например, на прием всех пакетов, проходящих по кабельному сегменту. Последнее может представлять интерес в диагностических целях, так как вслед за пакетным драйвером загружается Etherdrv, Winsock или winpkt и т.д., блокирующие режим приема всех пакетов (mode=6). Ниже приведен пример описания основных параметров драйвера:

BLUEBOOK

equ

1

 

IEEE8023

equ

11

 

ADDR_LEN

equ

6

; размер Ethernet-адреса

MAX_M_CAST

equ

8

; максимальное число мультикаст-адресов.


Public

int_no,

io_addr

 

int_no

db

2,0,0,0

; должно иметь 4 байта для get_number.

io_addr

dw

0300h,0

; I/O адрес карты (переключатели)


public

driver_class

driver_type,

driver_name,

driver_function,

parameter_list

driver_class

db

BLUEBOOK, IEEE8023, 0

; из спецификации интерфейса

driver_type

dw

54

; из спецификации интерфейса

driver_name

db

'NE2000',0

; имя драйвера.

driver_function

db

2

 

parameter_list

label

byte

 

 

db

1

;

 

db

9

;

 

db

14

; длина списка параметров в байтах

 

db

ADDR_LEN

; длина адреса MAC-уровня в байтах

 

dw

GIANT

; MTU, включая MAC-заголовок

 

dw

MAX_M_CAST * ADDR_LEN

 

; размер буфера для мультикаст-адресов

 

dw

0

;(# принимаемых подряд пакетов с; размером MTU) - 1

 

dw

0

; (# посылаемых подряд пакетов) - 1

int_num

dw

0

; Номер прерывания

Работа с пакетным драйвером в MS-DOS

Существует множество пакетных драйверов. Можно обнаружить несколько модификаций для одного и того же типа интерфейса. Эти драйверы могут быть ориентированы на работу в разных программных средах (Novell, UNIX, MS-DOS и т.д.) и иметь разные возможности. Для MS-DOS сложился неофициальный стандарт, который позволяет использовать драйвер для самых разных приложений. Драйвер может использовать минимум возможностей интерфейса (базовый уровень), реализовать более широкий набор функций (мультикастинг, сбор статистики и т.д.) или поддерживать практически все, на что способен данный прибор. В последнем случае он занимает больше места в памяти. Описания операций с пакетными драйверами, приведенные ниже, выполнены в нотации ассемблера IBM/PC. При написании программы следует помнить, что порядок байтов в Ethernet противоположен тому, который используется в вашей IBM/PC.

Пакетные драйверы используют программные прерывания в интервале 0x60 - 0x80. Следует сразу заметить, что не все прерывания из этого списка свободны и при конфигурировании системы следует проявлять осмотрительность. Для того чтобы избежать конфликтов с другими внешними устройствами, предусматривается возможность реконфигурации прерываний. Предполагается, что программа обработки прерываний начинается с команды безусловной передачи управления (JMP), за которой следует текстовая строка "PKT DRVR". Именно эта строка служит указателем при поиске адреса пакетного прерывания. Практически все драйверы могут работать с различными протоколами (TCP/IP, OSI и др.). Решить задачу мультиплексирования на связном уровне помогает процедура access_type, которая обеспечивает доступ для пакетов определенного типа.

Все функции реализуются с помощью обращения к драйверу с набором определенных параметров. При этом значение регистра AH определяет тип запроса. Каждому типу используемого сетевого протокола, с которым работает интерфейс, ставится в соответствие целочисленный указатель (handle), получаемый с помощью процедуры access_type. Выполнимость драйвером тех или иных операций может быть выяснена с помощью запроса driver_info.

При работе с драйвером следует проявлять осторожность и спасать нужные вам регистры. Следует также помнить, что порядок байтов в PC и в некоторых сетях, включая Ethernet, не совпадает. Описание основных запросов, посылаемых пакетному драйверу:

1. Получение информации о типе и функциональных возможностях драйвера

driver_info AH == 1,
AL == 255 (код запроса)

public

_driver_info

_driver_info

proc near

 

 

mov AX, 1FFH

; ah=1, al=255

 

call int_pkt

; обращение к драйверу

 

jnc lv

 

 

mov AX, seg _PARAM.ER_CODE

 

 

mov DS, AX

 

 

mov _PARAM.ER_CODE, 272

; Устанавливаем код "Нет инф. о драйвере"

lv:

ret

_driver_info

endp


int_pkt:

 

; Подпрограмма обращения к драйверу

 

push ds

 

 

push es

 

 

pushf

 

 

cli

 

 

call _param.Handler

; адрес _param.Handler должен быть определен раньше

 

pop es

 

 

pop ds

 

 

ret

 

Целочисленный указатель (handle) должен быть занесен в регистр BX (для старых драйверов). В случае ошибки устанавливается флаг carry, а код ошибки заносится в регистр DH. Сообщение BAD_HANDLE (неверный указатель) возможно только для старых драйверов. При благополучном исполнении флаг carry равен нулю, а в регистры будет занесены следующие параметры:

BX

версия;

CH

класс;

CL

номер;

DX

тип;

DS:SI

указывают на строку имени драйвера;

AL

функциональные возможности.

AL = 1

гарантируется выполнение базовых функций;

= 2

обеспечено выполнение базового и расширенного набора функций;

= 5

выполняется базовый и экстра-набор функций;

= 6

выполним полный набор функций;

= 255

драйвер не установлен.

Ниже приведен пример программы, реализующей некоторые из описанных запросов.

.MODEL

small

 

PUBLIC

_INFACE

 

VERSION

EQU

1

EXTRN

_PARAM:BYTE

 

EXTRN

_Q:BYTE

 

.DATA

INCLUDE

DEF.ASM

; Определения некоторых констант

P_LIST

STRUC

 

LINTN

DB

32 dup(0)

; Список активных номеров прерываний

HANDLES

DW

?

 

HANDLEP

DW

?

 

ER_CODE

DW

?

 

ERNUM

DW

?

; Код ошибки

HANDLER

DD

?

 

MODE

DW

?

; Текущий режим приема пакетов

MLIST

DB

0,0,0,0,0,0

; Список допустимых режимов; 1 => имеется

PKT_IN

DW

?,?

; Диагностический массив

pkt_out

DW

?,?

 

byte_in

DW

?,?

 

byt_out

DW

?,?

 

err_in

DW

?,?

 

err_out

DW

?,?

 

pk_drop

DW

?,?

 

L1

DW

0

; Версия драйвера

L2

DW

0

; класс/номер

L3

DW

0

; Тип

L4

DW

0

; Функция

_NAME

DB

0,0,0,0,0,0,0,0,0,0

; Имя интерфейса

ETHER_ADR

DB

ADDR_LEN dup(-1)

; Ethernet-адрес

S_ADR

DB

EADDR_LEN+5 dup(-1)

; Ethernet-адрес получателя

D_ADR

DB

EADDR_LEN+5 dup(-1)

; Ethernet-адрес отправителя

P_LIST

ENDS

QUEUE

STRUC

Leng

DW

15000,?

; Длина очереди

Tail

DW

?

; Смещение последнего элемента очереди

Head

DW

?

; Смещение первого элемента очереди

_end

DW

?

; Указатель на конец очереди

p_len

DW

?

; Длина пакета

P_start

DW

?

; Указатель на текущий пакет = Q_head - Q_begin +2

NEW

DB

0

; Флаг нового пакета

Line

DB

?

; Строка экрана

Npacks

DD

0

; Счетчик принятых пакетов

B

DW

?

; смещение Q_beg

Point

DW

380 dup(?)

 

Beg

DB

31000 dup(?)

; Пакетный буфер

QUEUE

ENDS

 

ether_bdcst

DB

EADDR_LEN dup(-1)

; Широковещательный адрес Ethernet, заполненный -1.

ether_addr

DB

EADDR_LEN dup(-1)

 

bogus_type

DB

0,0;

 

signature

DB

'PKT DRVR',0

; Сигнатура пакетного драйвера

signature_len

equ

$-signature

 

SAFE

DW

?

 

DFLAG

DB

0

 

.CODE

 

PUBLIC

_INFACE

_INFACE

PROC

NEAR


 

CLD

 

 

MOV DFLAG, 0

; Очистка флага драйвера

 

MOV _PARAM.ER_CODE, 0

; Очистка флага ошибки

 

PUSH BP

; Спасение регистров

 

MOV BP, SP

 

 

PUSH SI

 

 

PUSH DI

 

 

PUSH ES

 

 

PUSH DS

 


 

MOV CX, 32

 

 

MOV AL, 60H

; Установка начального номера прерывания

 

LEA SI, _PARAM.LINTN

; Формирование указателя на список номеров прерывания

CHECK:

PUSH AX

 

 

PUSH CX

 

 

PUSH SI

 

 

CALL CHK_INT

 

 

POP SI

 

 

POP CX

 

 

MOV byte ptr [SI], 0 ;

 

 

JNE NO_SIGNATURE

 

 

INC DFLAG

; Установка флага <Это драйвер>

 

MOV BYTE PTR [SI], 1

; Установка флага наличия

NO_SIGNATURE:

 

POP AX

 

 

INC AL

; Следующий номер прерывания

 

INC SI

; Актуализация указателя

 

LOOP CHECK

 


 

CMP DFLAG, 0

; Драйвер присутствует?

 

JNE HAVE_SIGNATURE

 

 

MOV _PARAM.ER_CODE, 271

; Установка флага <No signature>

 

JMP OKAY

 

INT_PKT:

 

PUSH ES

 

pushf

 

cli

 

call _PARAM.HANDLER

 

POP ES

 

RET


CHK_INT:

PUSH ES

; AL = номер прерывания

 

PUSH DI

 


 

MOV AH, 35H

; Получение вектора прерывания

 

INT 21H

; ES:BX=seg:offs драйвера


 

MOV _PARAM.HANDLER.OFFS,BX

; Записываем адрес драйвера

 

MOV _PARAM.HANDLER.SEGM, ES

 

 

LEA DI, 3[BX]

; Устанавливаем смещение сигнатуры драйвера

 

MOV SI, OFFSET SIGNATURE

; Проверка сигнатуры драйвера

 

MOV CX, SIGNATURE_LEN

; Присутствует ли здесь драйвер?

 

REPE CMPSB ; DS:[SI] - ES:[DI]

 


 

POP DI

 

POP ES

 

RET


HAVE_SIGNATURE:

 

MOV CX, 32

; Установка начального значения счетчика

 

LEA SI, _PARAM.LINTN

; Устанавливаем указатель списка

 

MOV AL, 60H

; Задаем начальный номер прерывания

CHOICE:

CMP BYTE PTR [SI], 0

 

 

JNE SETDRV

 

 

INC AL

 

 

LOOP CHOICE

 


SETDRV:

MOV AH, 35H

 

 

INT 21H

 

 

MOV _PARAM.HANDLER.OFFS,BX

; Определяем адрес драйвера

 

MOV _PARAM.HANDLER.SEGM, ES

 


 

PUSH DS

 

 

POP ES

 

 

MOV CX, EADDR_LEN

 

 

MOV SI, OFFSET ETHER_ADDR

 

 

MOV DI, OFFSET ETHER_BDCST

 

 

REPE CMPSB

 

 

JE GET_MODE

; Адрес не определен


 

MOV AH, 25

; Записываем ethernet-адрес

 

MOV DI, offset ETHER_ADDR

 

 

MOV CX, EADDR_LEN

 

 

call int_pkt

 

 

MOV _PARAM.ER_CODE, DX

; Устанавливаем код ошибки

 

JMP OKAY

 

GET_MODE:

 

MOV SAFE, DS

; Спасаем DS

 

PUSH DS

 

 

MOV AH, 2

; Открываем доступ пакетам

 

MOV AL, 1

; Класс интерфейса

 

MOV BX, -1

; Тип интерфейса

 

MOV DL, 0

; Номер интерфейса

 

MOV CX, 2

; Используем длину type = 2

 

MOV SI, OFFSET BOGUS_TYPE

 

 

PUSH CS

; ES:DI -> Receiver.

 

POP ES

 

 

MOV DI, OFFSET RECEIVER

 

 

call INT_PKT

 

 

JNC $_$

 

 

MOV _PARAM.ER_CODE, DX

; Устанавливаем код ошибки

$_$:

MOV _PARAM.HANDLES, AX

; Записываем указатель-Handle


 

MOV AH, 6

; Определяем ethernet-адрес интерфейса

 

PUSH DS

 

 

POP ES

 

 

MOV DI, offset _PARAM.ETHER_ADR

 

 

MOV CX, EADDR_LEN

 

 

MOV BX, _PARAM.HANDLES

 

 

call int_pkt

 

 

JNC NOBAD

 

 

MOV _PARAM.ER_CODE, 273

; Ошибка при определении Ethernet-адреса

 

POP DS

 

 

JMP OKAY

 

NOBAD:

 

MOV AX, 1FFH

; Запрашиваем информацию о драйвере

 

MOV BX, _PARAM.HANDLES

; Устанавливаем указатель

 

call INT_PKT

 

 

JNC N_BAD

 

 

MOV _PARAM.ER_CODE, 272

; Ошибка при получении информации о драйвере

 

POP DS

 

 

JMP OKAY

 


N_BAD:

PUSH DS

 

PUSH SS

&nsp;

POP DS

 

MOV ES, SAFE


 

MOV _PARAM.L1, BX

; Версия драйвера

 

MOV _PARAM.L2, CX

; номер/класс

 

MOV _PARAM.L3, DX

; Тип

 

MOV _PARAM.L4, AX

; Функциональность

 

LEA BX, _PARAM._NAME

 

 

POP DS

 

 

MOV CX, 8

 

ZFIND:

CMP byte ptr [SI], 0

 

 

MOV AL, byte ptr [SI]

 

 

MOV byte ptr ES:[BX], AL

 

 

JE ZERO_

 

 

INC SI

 

 

INC BX

 

 

LOOP ZFIND

 

ZERO_:

POP DS

 

 

MOV AH, 21

; Запрашиваем код режима приема пакетов

 

MOV BX, _PARAM.HANDLES

 

 

call INT_PKT

 

 

MOV _PARAM.MODE, AX

; Записываем код режима

.........................

OKAY:

POP DS

 

POP ES

 

POP DI

 

POP SI

 

MOV SP, BP

 

POP BP

 

RET


RECEIVER:

; Подпрограмма RECEIVER, вызываемая при получении пакета

 

OR AX, AX

; Первый или второй вызов?

 

JNE RECV

 

 

MOV AX, seg _Q.beg

; Указатель буфера ES:DI

 

MOV ES, AX

 

 

MOV DI, offset _Q.beg

 


RECV:

RETF

2. Организация доступа для пакетов данного типа
access_type(if_class, if_type, if_number, type, typelen, receiver)
AH ==2 (код запроса)

Запрос access_type инициализирует доступ для пакетов определенного типа (type). Аргумент typelen - длина спецификации типа в байтах, для PC/TCP равна 5 (наименьшее значение - 2, для IP и ARP). Аргумент receiver является указателем на подпрограмму, которая вызывается при приеме пакета. Получая пакет, драйвер дважды обращается к этой программе. Первый раз (при AX==0) это делается с целью получения адреса буфера, куда должен быть положен пакет. Прикладная программа в этом случае должна выдать указатель буфера в регистры ES:DI. Если прикладной процесс не имеет свободного буфера,то возвращается значение 0:0. Пакет выбрасывается и повторное обращение к программе receiver отменяется. Форма реализации запроса аналогична приведенному для driver_info:

Int

if_class; AL

; класс интерфейса

Int

if_type; BX

; тип интерфейса

Int

if_number; DL

; номер интерфейса

Char

far *type; DS:SI

 

Unsigned

typelen; CX

 

Int

(far *receiver); ES:DI

 


access:

mov ah, 2

 

 

mov al, ch

; установка класса; здесь предполагается, что содержимое регистров соответствует тому, что получено в результате обращения к driver_info

 

mov bx, dx

; устанавливаем параметр type

 

mov dl, cl

; устанавливаем параметр number, при одном интерфейсе number=0

 

xor cx, cx

; длина type равна нулю

 

push cs

; устанавливаем сегментный регистр receiver

 

pop es

 

 

mov di, offset RECEIVER

; вызов подпрограммы receiver

 

call int_pkt

; обращение к пакетному драйверу

В случае ошибки флаг carry=1, а в регистр DH заносится код ошибки. Возможные ошибки:

2

NO_CLASS не найдено интерфейса указанного класса;

3

NO_TYPE не найдено интерфейса указанного типа;

4

NO_NUMBER не найдено интерфейса с указанным номером;

5

BAD_TYPE специфицирован неправильный тип пакета;

9

NO_SPACE недостаточно места в памяти;

10

TYPE_INUSE было обращение к данному типу и он пока занят.

При успешном выполнении запроса флаг carry=0, а в регистр AX занесен указатель (handle).

Обращение к приемнику (receiver):

(*receiver)(handle, flag, len [, buffer])

int handle;

BX

; указатель

int flag;

AX

; флаг вызова(0/1)

unsigned len;

CX

; целое без знака - длина пакета

if AX == 1,

char far *buffer;

DS:SI

; адрес буфера

Если параметр typelen равен нулю, прикладной процесс готов получать все пакеты. Очень важно, чтобы при первом обращении к receiver (AX==0) CX (длина пакета) была указана правильно, что позволит выделить нужное место в памяти. CX должна включать в себя длину MAC-заголовка и размер самого сообщения без контрольной суммы (CRC). Повторный вызов (AX==1) программы receiver указывает на то,что пакет записан в буфер и прикладная программа может с ним работать. Адрес буфера будет указан в регистрах DS:SI.

3. Завершение доступа пакетов данного типа release_type

int release_type(handle) AH == 3;
код запроса int handle;
BX ; указатель определяет тип пакетов

_release_type proc near

 

push bp

; спасение регистров

 

push ds

 

 

push es

 

 

mov ah, 3

; задаем код запроса

 

mov bx, _param.handle

; заносим указатель

 

pushf

 

 

cli

 

 

call _param.handler

; обращение к драйверу

 

mov _param.er_CODE, dx

; занесение кода ошибки

 

pop es

; восстановление регистров

 

pop ds

 

 

pop bp

 

 

ret

 

 

_release_type

endp

В случае ошибки флаг carry=1, а в регистр DH заносится код ошибки. Возможная ошибка: BAD_HANDLE (не верный указатель). При успешном выполнении запроса флаг carry=0. Эта операция прерывает доступ пакетов, соответствующих указателю, полученному с помощью запроса access_type. Старый указатель после выполнения этого запроса не действителен.

4. Процедура посылки пакета send_packet(buffer, length)

AH == 4 (код запроса)
char far *buffer; DS:SI (адрес буфера)
unsigned length; CX (длина пакета в байтах)

В случае ошибки флаг carry=1, а в регистр DH заносится код ошибки 12 CANT_SEND. send_packet отправляет пакет с числом байт, равным CX. Пакет должен в исходный момент лежать, начиная с адреса DS:SI. Прикладная программа должна сформировать все необходимые заголовки. Информация, нужная для осуществления демультиплексирования пакетов (MAC или LLC), также должна быть записана в пакет, так как при этом запросе не сообщается значение указателя (handle).

5. Завершение работы драйвера terminate(handle)

AH == 5 (код запроса)
int handle; BX (указатель)

В случае ошибки флаг carry=1, а в регистр DH заносится код ошибки. Возможные ошибки:

1 BAD_HANDLE;
7 CANT_TERMINATE.

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

6. Получение физического адреса интерфейса get_address(handle,buf,len)

AH == 6 (код запроса)
int handle; BX (указатель)
char far *buf; ES:DI (адрес буфера)
int len; CX (длина адреса в байтах)

В случае ошибки флаг carry=1, а в регистр DH заносится код ошибки. Возможные ошибки:

1 BAD_HANDLE;
9 NO_SPACE. При успешном выполнении запроса флаг carry=0, а в регистр CX занесена длина адреса.

Копирует текущее значение сетевого (физического) адреса интерфейса в буфер. Если получено сообщение NO_SPACE, это означает, что выделенного места (len=CX) для копирования адреса не хватило.

7. Возвращение интерфейса в исходное состояние reset_interface(handle)

AH == 7 (код запроса)
int handle; BX (указатель)

В случае ошибки флаг carry=1, а в регистр DH заносится код ошибки. Возможные ошибки:

1 BAD_HANDLE;
15 CANT_RESET.

Возвращает интерфейс в исходное состояние, прерывая все процессы. Местное значение физического сетевого адреса, если оно было изменено, восстанавливается из ROM, прием переключается в режим 3, а список мультикастинг-адресов обнуляется. При работе с несколькими указателями (handle) возможны серьезные неприятности, по этому выполнение запроса блокируется и присылается сообщение CANT_RESET.

8. Запрос установки режима приема пакетов set_rcv_mode(handle,mode)

AH == 20 (код запроса) int handle;
BX (входные параметры - указатель) int mode;
CX (код режима приема пакетов)

В случае ошибки флаг carry=1, а в регистр DH заносится код ошибки. Возможные ошибки:

1 BAD_HANDLE;
8 BAD_MODE.

Устанавливает режим приема пакетов. Режим 3 используется по умолчанию. Возможны (но не для всех интерфейсов) следующие режимы:

Режим

Значение

1

выключение приема пакетов;

2

прием пакетов, адресованных только данному интерфейсу;

3

режим 2 плюс бродкастинг-пакеты;

4

режим 3 плюс некоторые мультикастинг-пакеты;

5

режим 3 плюс все мультикастинг-пакеты;

6

все пакеты.

9. Считывание действующего режима приема пакетов get_rcv_mode(handle)

AH == 21 (код запроса)

int handle; BX (входной параметр - указатель)

В случае ошибки флаг carry=1, а в регистр DH заносится код ошибки 1 BAD_HANDLE. При успешном выполнении запроса флаг carry=0, а в регистр AX заносится код режима приема пакетов.

10. Занесение списка мультикастинг-адресов в интерфейс set_multicast_list(addrlst,len)

AH == 22 (код запроса)
char far *addrlst; ES:DI (адрес буфера, где лежат адреса)
int len; CX (длина списка адресов)

В случае ошибки флаг carry=1, а в регистр DH заносится код ошибки. Возможные ошибки:

6 NO_MULTICAST;
9 NO_SPACE;
14 BAD_ADDRESS.

Список адресов представляет собой счетную последовательность, начинающуюся с байта числа адресов в списке. На список адресов указывает комбинация регистров ES:DI. Сообщение NO_SPACE присылается, если указатель адреса отсутствует, или число адресов превосходит аппаратные возможности интерфейса. Прежде чем заносить список, полезно сначала ознакомиться с имеющимся уже списком, выполнив запрос get_multicast_list. При получении сообщения NO_SPACE рекомендуется попытаться установить режим приема 3 с помощью запроса set_rcv_mode.

11. Получение рабочего списка мультикастинг-адресов

get_multicast_list

AH == 23 (код запроса)

В случае ошибки флаг carry=1, а в регистр DH заносится код ошибки. Возможные ошибки:

6 NO_MULTICAST;
9 NO_SPACE.

При успешном выпонении запроса флаг carry=0, в регистр CX заносится длина списка адресов, а регистры ES:DI указывают на начало счетной оследовательности, где запрошенный список лежит. Прикладная программа не должна модифицировать этот список.

12. Получение статистических данных об ошибках и трафике через данный интерфейсget_statistics(handle)

AH == 24 (код запроса)
int handle; BX (указатель)
char far *statistics; DS:SI (адрес буфера, куда записываются статистические данные)

В случае ошибки флаг carry=1, а в регистр DH заносится код ошибки 1 BAD_HANDLE. При успешном выполнении запроса флаг carry=0, а в массиве, начиная с адреса DS:SI, лежит запрошенная информация.

struct statistics {

unsigned long packets_in;

( Число принятых пакетов для всех указателей)

unsigned long packets_out;

( Число посланных пакетов)

unsigned long bytes_in;

( Число принятых байтов, включая MAC заголовки)

unsigned long bytes_out;

( Число посланных байтов)

unsigned long errors_in;

( Полное число ошибок при приеме)

unsigned long errors_out;

( Число ошибок при посылке пакетов)

unsigned long packets_lost;

( Число потерянных пакетов из-за отсутствия свободного буфера или других ресурсов)

};

Статистические данные имеют вид целых 32-разрядных чисел в формате IBM/PC.

13. Смена физического адреса интерфейса

set_address(addr, len) AH == 25
char far *addr; ES:DI (адрес буфера, где лежит новое значение адреса)
int len; CX (длина адреса в байтах)

В случае ошибки флаг carry=1, а в регистр DH заносится код ошибки. Возможные ошибки:

13 CANT_SET;
14 BAD_ADDRESS.

При благоприятном выполнении запроса флаг carry=0, а значение регистра CX сохраняется.

Запрос используется в случае, когда необходим специфический физический адрес интерфейса (например, в случае DECNET). При наличии более одного указателя (handle) драйвер откажется исполнить данный запрос и пришлет сообщение CANT_SET.

Этим не исчерпывается перечень возможных запросов, существует некоторое количество операций, относящихся к экстра-набору функций (код функциональности 5 или 6, смотри описание запроса driver_info).

Previous: 7.1 Winsock (для UNIX, Windows-95 и -NT)    UP: 7 Программирование для сетей (новые идеи, принципы и возможности)
Down: 8 Заключение    Next: 8 Заключение




Спонсоры:
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2021 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру