12,7 → 12,30 |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|
; IP underlying protocols numbers |
PROTOCOL_ICMP equ 1 |
PROTOCOL_TCP equ 6 |
PROTOCOL_UDP equ 17 |
|
struc IP_PACKET |
{ .VersionAndIHL db ? ;+00 - Version[0-3 bits] and IHL(header length)[4-7 bits] |
.TypeOfService db ? ;+01 |
.TotalLength dw ? ;+02 |
.Identification dw ? ;+04 |
.FlagsAndFragmentOffset dw ? ;+06 - Flags[0-2] and FragmentOffset[3-15] |
.TimeToLive db ? ;+08 |
.Protocol db ? ;+09 |
.HeaderChecksum dw ? ;+10 |
.SourceAddress dd ? ;+12 |
.DestinationAddress dd ? ;+16 |
.DataOrOptional dd ? ;+20 |
} |
|
virtual at 0 |
IP_PACKET IP_PACKET |
end virtual |
|
|
;******************************************************************* |
; Interface |
; |
24,179 → 47,151 |
;******************************************************************* |
|
|
; |
; IP Packet after reception - Normal IP packet format |
; |
; 0 1 2 3 |
; 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 |
; |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
;0 |Version| IHL |Type of Service| Total Length | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
;4 | Identification |Flags| Fragment Offset | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
;8 | Time to Live | Protocol | Header Checksum | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
;12 | Source Address | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
;16 | Destination Address | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
;20 | Data | |
; +-+-+-.......... -+ |
; |
; |
; [smb] attention! according to RFC 791 IP packet may have 'options' sections, |
; so we can't simply think, that data have offset 20. We must calculate offset from |
; IHL field |
; |
macro GET_IHL reg, header_addr |
{ |
movzx reg, byte [header_addr] |
|
; we need 4-7 bits, so.... |
and reg, 0x0000000F |
|
; IHL keeps number of octets, so we need to << 2 'reg' |
shl reg, 2 |
} |
|
|
;*************************************************************************** |
; Function |
; ip_rx |
; |
; Description |
; Handles received IP packets |
; This is a kernel function, called by stack_handler |
; Processes all IP-packets received by the network layer |
; It calls the appropriate protocol handler |
; |
;*************************************************************************** |
ip_rx: |
proc ip_rx stdcall |
local buffer_number dd ? |
|
; Look for a buffer to tx |
mov eax, IPIN_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
je ipr_exit ; Exit if no buffer available |
je .exit ; Exit if no buffer available |
|
push eax |
mov [buffer_number], eax ;save buffer number |
|
; convert buffer pointer eax to the absolute address |
mov ecx, IPBUFFSIZE |
mul ecx |
imul eax, IPBUFFSIZE |
add eax, IPbuffs |
|
mov edx, eax ; Save the address in edx for use by future processes |
mov ebx, eax ; ebx=pointer to IP_PACKET |
|
; Validate the IP checksum |
mov ebx, edx |
mov ah, [ebx + 10] |
mov al, [ebx + 11] ; Get the checksum in intel format |
mov [ebx + 10], word 0 ; clear checksum field - need to when |
mov dx, word[ebx + IP_PACKET.HeaderChecksum] |
xchg dh,dl ; Get the checksum in intel format |
|
mov [ebx + IP_PACKET.HeaderChecksum], word 0 ; clear checksum field - need to when |
; recalculating checksum |
|
; this needs two data pointers and two size #. |
; 2nd pointer can be of length 0 |
mov ebx, edx |
mov [checkAdd1], ebx |
mov [checkSize1], word 20 |
mov [checkAdd2], dword 0 |
mov [checkSize2], word 0 |
|
call checksum ; Recalculate IP checksum |
cmp ax, [checkResult] |
jnz ipr_dump |
GET_IHL ecx, ebx + IP_PACKET.VersionAndIHL ;get packet length in ecx |
stdcall checksum_jb, ebx, ecx ;buf_ptr, buf_size |
cmp dx, ax |
|
mov edx, ebx ; EDX (IP-BUFFER POINTER) WILL BE USED FOR *_rx HANDLERS BELOW!!! |
jnz .dump ;if CHECKSUM isn't valid then dump packet |
|
; Validate the IP address, if it isn't broadcast |
mov eax, [stack_ip] |
cmp dword[ebx + IP_PACKET.DestinationAddress], eax |
je @f |
|
; If the IP address is 255.255.255.255, accept it |
; - it is a broadcast packet, which we need for dhcp |
mov eax, [edx + 16] |
cmp eax, 0xffffffff |
je ipr_p0 |
cmp dword[ebx + IP_PACKET.DestinationAddress], 0xffffffff |
jne .dump |
|
; Validate the IP address, if it isn't broadcast |
cmp eax, [stack_ip] |
jnz ipr_dump |
@@: |
mov al, [ebx + IP_PACKET.VersionAndIHL] |
and al, 0x0f ;get IHL(header length) |
cmp al, 0x05 ;if IHL!= 5*4(20 bytes) |
jnz .dump ;then dump it |
|
ipr_p0: |
mov al, [edx] |
and al, 0x0f |
cmp al, 0x05 |
jnz ipr_dump |
cmp byte[ebx + IP_PACKET.TimeToLive], byte 0 |
je .dump ;if TTL==0 then dump it |
|
cmp [edx+8], byte 0 |
jz ipr_dump |
mov ax, word[ebx + IP_PACKET.FlagsAndFragmentOffset] |
and ax, 0xFFBF ;get flags |
cmp ax, 0 ;if some flags was set then we dump this packet |
jnz .dump ;the flags should be used for fragmented packets |
|
mov ax, [edx + 6] |
and ax, 0xFFBF |
cmp ax, 0 |
jnz ipr_dump |
|
; Check the protocol, and call the appropriate handler |
; Each handler will re-use or free the queue buffer as appropriate |
mov al, [edx + 9] |
cmp al , PROTOCOL_ICMP |
jnz ipr_p1 |
pop eax |
call icmp_rx |
jmp ipr_exit |
|
ipr_p1: |
mov al, [ebx + IP_PACKET.Protocol] |
|
cmp al , PROTOCOL_TCP |
jnz ipr_p2 |
pop eax |
jne .not_tcp |
DEBUGF 1,"K : ip_rx - TCP packet\n" |
mov eax, dword[buffer_number] |
call tcp_rx |
jmp ipr_exit |
jmp .exit |
|
ipr_p2: |
.not_tcp: |
cmp al , PROTOCOL_UDP |
jnz ipr_dump |
pop eax |
jne .not_udp |
DEBUGF 1,"K : ip_rx - UDP packet\n" |
mov eax, dword[buffer_number] |
call udp_rx |
jmp ipr_exit |
jmp .exit |
|
ipr_dump: |
.not_udp: |
cmp al , PROTOCOL_ICMP |
jne .dump ;protocol ain't supported |
|
DEBUGF 1,"K : ip_rx - ICMP packet\n" |
;GET_IHL ecx, ebx + IP_PACKET.VersionAndIHL ;get packet length in ecx |
mov eax, dword[buffer_number] |
stdcall icmp_rx,eax,ebx,ecx ;buffer_number,IPPacketBase,IPHeaderLength |
jmp .exit |
|
|
.dump: |
; No protocol handler available, so |
; silently dump the packet, freeing up the queue buffer |
|
; inc dword [dumped_rx_count] |
inc dword [dumped_rx_count] |
|
pop eax |
mov eax, dword[buffer_number] |
call freeBuff |
|
ipr_exit: |
.exit: |
ret |
endp |
|
|
|
;*************************************************************************** |
; Function |
; icmp_rx |
; |
; Description |
; ICMP protocol handler |
; This is a kernel function, called by ip_rx |
; edx contains the address of the buffer in use. |
; This buffer must be reused or marked as empty afterwards |
; |
;*************************************************************************** |
icmp_rx: |
cmp [edx + 20], byte 8 ; Is this an echo request? discard if not |
jz icmp_echo |
|
call freeBuff |
jmp icmp_exit |
|
icmp_echo: |
push eax |
mov [edx + 10], word 0 ; I think this was already done by IP rx |
|
; swap the source and destination addresses |
mov ecx, [edx + 16] |
mov eax, [edx + 12] |
mov [edx + 16], eax |
mov [edx + 12], ecx |
|
; recaluculate the IP header checksum |
|
mov ebx, edx |
mov [checkAdd1], ebx |
mov [checkSize1], word 20 |
mov [checkAdd2], dword 0 |
mov [checkSize2], word 0 |
|
call checksum |
mov ax, [checkResult] |
mov [edx + 10], ah |
mov [edx + 11], al ; ?? correct byte order? |
|
mov [edx + 20], byte 0 ; change the request to a response |
mov [edx + 22], word 0 ; clear ICMP checksum prior to re-calc |
|
; Calculate the length of the ICMP data ( IP payload) |
mov ah, [edx + 2] |
mov al, [edx + 3] |
sub ax, 20 |
|
mov [checkSize1], ax |
mov ebx, edx |
add ebx, 20 |
|
mov [checkAdd1], ebx |
mov [checkAdd2], dword 0 |
mov [checkSize2], word 0 |
|
call checksum |
|
mov ax, [checkResult] |
mov [edx + 22], ah |
mov [edx + 23], al |
|
; Queue packet for transmission |
|
pop ebx |
mov eax, NET1OUT_QUEUE |
call queue |
|
icmp_exit: |
ret |