Телекоммуникационные технологии. Том 1

       

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


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

public_driver_info
_driver_infoproc 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_infoendp

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драйвер не установлен.

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

.MODELsmall 
PUBLIC_INFACE 
VERSIONEQU1
EXTRN_PARAM:BYTE 
EXTRN_Q:BYTE 

.DATA

INCLUDEDEF.ASM; Определения некоторых констант
P_LISTSTRUC 
LINTNDB32 dup(0); Список активных номеров прерываний
HANDLESDW? 
HANDLEPDW? 
ER_CODEDW? 
ERNUMDW?; Код ошибки
HANDLERDD? 
MODEDW?; Текущий режим приема пакетов
MLISTDB0,0,0,0,0,0; Список допустимых режимов; 1 => имеется
PKT_INDW?,?; Диагностический массив
pkt_outDW?,? 
byte_inDW?,? 
byt_outDW?,? 
err_inDW?,? 
err_outDW?,? 
pk_dropDW?,? 
L1DW0; Версия драйвера
L2DW0; класс/номер
L3DW0; Тип
L4DW0; Функция
_NAMEDB0,0,0,0,0,0,0,0,0,0; Имя интерфейса
ETHER_ADRDBADDR_LEN dup(-1); Ethernet-адрес
S_ADRDBEADDR_LEN+5 dup(-1); Ethernet-адрес получателя
D_ADRDBEADDR_LEN+5 dup(-1); Ethernet-адрес отправителя
P_LISTENDS


QUEUESTRUC
LengDW15000,?; Длина очереди
TailDW?; Смещение последнего элемента очереди
HeadDW?; Смещение первого элемента очереди
_endDW?; Указатель на конец очереди
p_lenDW?; Длина пакета
P_startDW?; Указатель на текущий пакет = Q_head - Q_begin +2
NEWDB0; Флаг нового пакета
LineDB?; Строка экрана
NpacksDD0; Счетчик принятых пакетов
BDW?; смещение Q_beg
PointDW380 dup(?) 
BegDB31000 dup(?); Пакетный буфер
QUEUEENDS
 
ether_bdcstDBEADDR_LEN dup(-1); Широковещательный адрес Ethernet, заполненный -1.
ether_addrDBEADDR_LEN dup(-1) 
bogus_typeDB0,0; 
signatureDB'PKT DRVR',0; Сигнатура пакетного драйвера
signature_lenequ$-signature 
SAFEDW? 
DFLAGDB0 
.CODE
 PUBLIC_INFACE
_INFACEPROCNEAR
 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:
Intif_class; AL; класс интерфейса
Intif_type; BX; тип интерфейса
Intif_number; DL; номер интерфейса
Charfar *type; DS:SI 
Unsignedtypelen; 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 не найдено интерфейса указанного класса;
3NO_TYPE не найдено интерфейса указанного типа;
4NO_NUMBER не найдено интерфейса с указанным номером;
5BAD_TYPE специфицирован неправильный тип пакета;
9NO_SPACE недостаточно места в памяти;
10TYPE_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.


Содержание раздела