Получение информации о типе и функциональных возможностях драйвера
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] | |
<
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 | |
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 | |
| style="font-family:arial;font-size:12pt"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.
Содержание раздела