0,0 → 1,1784 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; STACK.INC ;; |
;; ;; |
;; TCP/IP stack for Menuet OS ;; |
;; ;; |
;; Version 0.7 4th July 2004 ;; |
;; ;; |
;; Copyright 2002 Mike Hibbett, mikeh@oceanfree.net ;; |
;; ;; |
;; See file COPYING for details ;; |
;; ;; |
;; Version 0.7 ;; |
;; Added a timer per socket to allow delays when rx window ;; |
;; gets below 1KB ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|
|
;******************************************************************* |
; Interface |
; The interfaces defined in ETHERNET.INC plus: |
; stack_init |
; stack_handler |
; app_stack_handler |
; app_socket_handler |
; checksum |
; |
;******************************************************************* |
|
|
|
; |
; IP Packet after reception - Normal IP packet format |
; |
; 0 1 2 3 |
; 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
; |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
;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 | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; | Data | |
; +-+-+-.......... -+ |
|
|
; TCP Payload ( Data field in IP datagram ) |
; |
; 0 1 2 3 |
; 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
;20 | Source Port | Destination Port | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
;24 | Sequence Number | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
;28 | Acknowledgment Number | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
;32 | Data | |U|A|P|R|S|F| | |
; | Offset| Reserved |R|C|S|S|Y|I| Window | |
; | | |G|K|H|T|N|N| | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
;36 | Checksum | Urgent Pointer | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
;40 | Options | Padding | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; | data |
|
|
; |
; UDP Payload ( Data field in IP datagram ) |
; |
; 0 1 2 3 |
; 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
; |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; | Source Port | Destination Port | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; | Length ( UDP Header + Data ) | Checksum | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; | UDP Data | |
; +-+-+-.......... -+ |
; |
|
|
; |
; Socket Descriptor + Buffer |
; |
; 0 1 2 3 |
; 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
; |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; | Status ( of this buffer ) | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; | Application Process ID | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; | Local IP Address | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; | Local IP Port | Unused ( set to 0 ) | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; | Remote IP Address | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; | Remote IP Port | Unused ( set to 0 ) | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 24| Rx Data Count INTEL format| |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 28| TCB STATE INTEL format| |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 32| TCB Timer (seconds) INTEL format| |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 36| ISS (Inital Sequence # used by this connection ) INET format| |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 40| IRS ( Inital Receive Sequence # ) INET format| |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 44| SND.UNA Seq # of unack'ed sent packets INET format| |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 48| SND.NXT Next send seq # to use INET format| |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 52| SND.WND Send window INET format| |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 56| RCV.NXT Next expected receive sequence # INET format| |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 60| RCV.WND Receive window INET format| |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 64| SEG.LEN Segment length INTEL format| |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 68| SEG.WND Segment window INTEL format| |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 72| Retransmit queue # NOW WINDOW SIZE TIMER INTEL format| |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
; 76| RX Data | |
; +-+-+-.......... -+ |
|
|
|
; IP protocol numbers |
PROTOCOL_ICMP equ 1 |
PROTOCOL_TCP equ 6 |
PROTOCOL_UDP equ 17 |
|
|
; TIPBUFF status values |
BUFF_EMPTY equ 0 |
BUFF_RX_FULL equ 1 |
BUFF_ALLOCATED equ 2 |
BUFF_TX_FULL equ 3 |
|
NUM_IPBUFFERS equ 20 ; buffers allocated for TX/RX |
|
SOCK_EMPTY equ 0 ; socket not in use |
SOCK_OPEN equ 1 ; open issued, but no data sent |
|
; TCP opening modes |
SOCKET_PASSIVE equ 0 |
SOCKET_ACTIVE equ 1 |
|
; TCP TCB states |
TCB_LISTEN equ 1 |
TCB_SYN_SENT equ 2 |
TCB_SYN_RECEIVED equ 3 |
TCB_ESTABLISHED equ 4 |
TCB_FIN_WAIT_1 equ 5 |
TCB_FIN_WAIT_2 equ 6 |
TCB_CLOSE_WAIT equ 7 |
TCB_CLOSING equ 8 |
TCB_LAST_ACK equ 9 |
TCB_TIME_WAIT equ 10 |
TCB_CLOSED equ 11 |
|
TWOMSL equ 10 ; # of secs to wait before closing socket |
|
; socket buffers |
SOCKETBUFFSIZE equ 4096 ; state + config + buffer. |
SOCKETHEADERSIZE equ 76 ; thus 4096 - SOCKETHEADERSIZE bytes data |
|
NUM_SOCKETS equ 16 ; Number of open sockets supported. Was 20 |
|
|
NUMQUEUES equ 4 |
EMPTY_QUEUE equ 0 |
IPIN_QUEUE equ 1 |
IPOUT_QUEUE equ 2 |
NET1OUT_QUEUE equ 3 |
|
NO_BUFFER equ 0xFFFF |
IPBUFFSIZE equ 1500 ; MTU of an ethernet packet |
NUMQUEUEENTRIES equ NUM_IPBUFFERS |
NUMRESENDENTRIES equ 18 ; Buffers for TCP resend packets |
TCP_RETRIES equ 5 ; Number of times to resend a packet |
TCP_TIMEOUT equ 10 ; resend if not replied to in x hs |
|
; These are the 0x40 function codes for application access to the stack |
STACK_DRIVER_STATUS equ 52 |
SOCKET_INTERFACE equ 53 |
|
|
; 128KB allocated for the stack and network driver buffers and other |
; data requirements |
stack_data_start equ 0x700000 |
eth_data_start equ 0x700000 |
stack_data equ 0x704000 |
stack_data_end equ 0x71ffff |
|
; 32 bit word |
stack_config equ stack_data |
; 32 bit word - IP Address in network format |
stack_ip equ stack_data + 4 |
; 1 byte. 0 == inactive, 1 = active |
slip_active equ stack_data + 8 ; no longer used |
; 1 byte. 0 == inactive, 1 = active |
ethernet_active equ stack_data + 9 |
unused equ stack_data + 10 |
; word. Buffer number, -1 if none |
rx_buff_ptr equ stack_data + 12 |
; dword. Buffer number, -1 if none |
tx_buff_ptr equ stack_data + 16 |
; byte. |
slip_rx_state equ stack_data + 20 ; no longer used |
; byte |
slip_tx_state equ stack_data + 21 ; no longer used |
; dword. Index into data |
rx_data_ptr equ stack_data + 22 |
; dword. Index into data |
tx_data_ptr equ stack_data + 26 |
; word. Count of bytes to send |
tx_msg_len equ stack_data + 30 |
; Address of selected socket |
sktAddr equ stack_data + 32 |
; Parameter to checksum routine - data ptr |
checkAdd1 equ stack_data + 36 |
; Parameter to checksum routine - 2nd data ptr |
checkAdd2 equ stack_data + 40 |
; Parameter to checksum routine - data size |
checkSize1 equ stack_data + 44 |
; Parameter to checksum routine - 2nd data size |
checkSize2 equ stack_data + 46 |
; result of checksum routine |
checkResult equ stack_data + 48 |
|
; holds the TCP/UDP pseudo header. SA|DA|0|prot|UDP len| |
pseudoHeader equ stack_data + 50 |
|
; receive and transmit IP buffer allocation |
sockets equ stack_data + 62 |
Next_free2 equ sockets + (SOCKETBUFFSIZE * NUM_SOCKETS) |
; 1560 byte buffer for rx / tx ethernet packets |
Ether_buffer equ Next_free2 |
Next_free3 equ Ether_buffer + 1560 |
last_1sTick equ Next_free3 |
IPbuffs equ Next_free3 + 1 |
queues equ IPbuffs + ( NUM_IPBUFFERS * IPBUFFSIZE ) |
queueList equ queues + (2 * NUMQUEUES) |
last_1hsTick equ queueList + ( 2 * NUMQUEUEENTRIES ) |
|
;resendQ equ queueList + ( 2 * NUMQUEUEENTRIES ) |
;resendBuffer equ resendQ + ( 4 * NUMRESENDENTRIES ) ; for TCP |
; equ resendBuffer + ( IPBUFFSIZE * NUMRESENDENTRIES ) |
|
|
|
resendQ equ 0x770000 |
resendBuffer equ resendQ + ( 4 * NUMRESENDENTRIES ) ; for TCP |
|
|
;*************************************************************************** |
; Function |
; stack_init |
; |
; Description |
; Clear all allocated memory to zero. This ensures that |
; on startup, the stack is inactive, and consumes no resources |
; This is a kernel function, called prior to the OS main loop |
; in set_variables |
; |
;*************************************************************************** |
stack_init: |
xor eax,eax |
mov edi,stack_data_start |
mov ecx,0x20000 / 4 ; Assume that we have 128KB of data |
cld |
rep stosd |
|
; Initialise TCP resend queue data structures |
mov eax, 0xFFFFFFFF |
mov edi, resendQ |
mov ecx, NUMRESENDENTRIES ; 1 dword per entry |
cld |
rep stosd |
|
|
mov eax, 0xFFFFFFFF |
mov [rx_buff_ptr], eax |
mov [tx_buff_ptr], eax |
|
; Put in some defaults : slip, 0x3f8, 4, ip=192.168.1.22 |
; Saves me entering them each boot up when debugging |
mov eax, 0x03f80401 |
mov [stack_config], eax |
mov eax, 0xc801a8c0 |
mov [stack_ip], eax |
|
call queueInit |
|
; The following block sets up the 1s timer |
mov al,0x0 |
out 0x70,al |
in al,0x71 |
mov [last_1sTick], al |
|
ret |
|
|
|
;*************************************************************************** |
; Function |
; stack_handler |
; |
; Description |
; The kernel loop routine for the stack |
; This is a kernel function, called in the main loop |
; |
;*************************************************************************** |
stack_handler: |
|
call ethernet_driver |
call ip_rx |
|
|
; Test for 10ms tick, call tcp timer |
mov eax, [timer_ticks] ;[0xfdf0] |
cmp eax, [last_1hsTick] |
je sh_001 |
|
mov [last_1hsTick], eax |
call tcp_tx_handler |
|
sh_001: |
|
; Test for 1 second event, call 1s timer functions |
mov al,0x0 ;second |
out 0x70,al |
in al,0x71 |
cmp al, [last_1sTick] |
je sh_exit |
|
mov [last_1sTick], al |
|
call arp_timer |
call tcp_tcb_handler |
|
sh_exit: |
ret |
|
|
|
|
;*************************************************************************** |
; Function |
; is_localport_unused |
; |
; Description |
; scans through all the active sockets , looking to see if the |
; port number specified in bx is in use as a localport number. |
; This is useful when you want a to generate a unique local port |
; number. |
; On return, eax = 1 for free, 0 for in use |
; |
;*************************************************************************** |
is_localport_unused: |
mov al, bh |
mov ah, bl |
mov bx, ax |
|
mov edx, SOCKETBUFFSIZE * NUM_SOCKETS |
mov ecx, NUM_SOCKETS |
mov eax, 0 ; Assume the return value is 'in use' |
|
ilu1: |
sub edx, SOCKETBUFFSIZE |
cmp [edx + sockets + 12], bx |
loopnz ilu1 ; Return back if the socket is occupied |
|
jz ilu_exit |
inc eax ; return port not in use |
|
ilu_exit: |
ret |
|
|
|
;*************************************************************************** |
; Function |
; get_free_socket |
; |
; Description |
; |
;*************************************************************************** |
get_free_socket: |
push ecx |
mov eax, SOCKETBUFFSIZE * NUM_SOCKETS |
mov ecx, NUM_SOCKETS |
|
gfs1: |
sub eax, SOCKETBUFFSIZE |
cmp [eax + sockets], dword SOCK_EMPTY |
loopnz gfs1 ; Return back if the socket is occupied |
mov eax, ecx |
pop ecx |
jz gfs_exit |
mov eax, 0xFFFFFFFF |
|
gfs_exit: |
ret |
|
|
|
;*************************************************************************** |
; Function |
; checksum |
; |
; Description |
; checkAdd1,checkAdd2, checkSize1, checkSize2, checkResult |
; Dont break anything; Most registers are used by the caller |
; This code is derived from the 'C' source, cksum.c, in the book |
; Internetworking with TCP/IP Volume II by D.E. Comer |
; |
;*************************************************************************** |
checksum: |
pusha |
|
xor edx, edx ; edx is the accumulative checksum |
xor ebx, ebx |
mov cx, [checkSize1] |
shr cx, 1 |
jz cs1_1 |
|
mov eax, [checkAdd1] |
|
cs1: |
mov bh, [eax] |
mov bl, [eax + 1] |
|
add eax, 2 |
add edx, ebx |
|
loopw cs1 |
|
cs1_1: |
and word [checkSize1], 0x01 |
jz cs_test2 |
|
mov bh, [eax] |
xor bl, bl |
|
add edx, ebx |
|
cs_test2: |
mov cx, [checkSize2] |
cmp cx, 0 |
jz cs_exit ; Finished if no 2nd buffer |
|
shr cx, 1 |
jz cs2_1 |
|
mov eax, [checkAdd2] |
|
cs2: |
mov bh, [eax] |
mov bl, [eax + 1] |
|
add eax, 2 |
add edx, ebx |
|
loopw cs2 |
|
cs2_1: |
and word [checkSize2], 0x01 |
jz cs_exit |
|
mov bh, [eax] |
xor bl, bl |
|
add edx, ebx |
|
cs_exit: |
mov ebx, edx |
|
shr ebx, 16 |
and edx, 0xffff |
add edx, ebx |
mov eax, edx |
shr eax, 16 |
add edx, eax |
not dx |
|
mov [checkResult], dx |
popa |
ret |
|
|
|
|
;*************************************************************************** |
; Function |
; app_stack_handler |
; |
; Description |
; This is an application service, called by int 0x40 fn 52 |
; It provides application access to the network interface layer |
; |
;*************************************************************************** |
app_stack_handler: |
cmp eax, 0 |
jnz not0 |
; Read the configuartion word |
mov eax, [stack_config] |
ret |
|
not0: |
cmp eax, 1 |
jnz not1 |
; read the IP address |
|
mov eax, [stack_ip] |
ret |
|
not1: |
cmp eax, 2 |
jnz not2 |
|
; write the configuration word |
mov [stack_config], ebx |
|
; <Slip shouldn't be active anyway - thats an operational issue.> |
; If ethernet now enabled, probe for the card, reset it and empty |
; the packet buffer |
; If all successfull, enable the card. |
; If ethernet now disabled, set it as disabled. Should really |
; empty the tcpip data area too. |
|
; ethernet interface is '3' in ls 7 bits |
and bl, 0x7f |
cmp bl, 3 |
|
je ash_eth_enable |
; Ethernet isn't enabled, so make sure that the card is disabled |
mov [ethernet_active], byte 0 |
|
ret |
|
ash_eth_enable: |
; Probe for the card. This will reset it and enable the interface |
; if found |
call eth_probe |
cmp eax, 0 |
je ash_eth_done ; Abort if no hardware found |
|
mov [ethernet_active], byte 1 |
|
ash_eth_done: |
ret |
|
not2: |
cmp eax, 3 |
jnz not3 |
; write the IP Address |
mov [stack_ip], ebx |
ret |
|
not3: |
cmp eax, 4 |
jnz not4 |
; Enabled the slip driver on the comm port |
; slip removed |
ret |
|
not4: |
cmp eax, 5 |
jnz not5 |
; Disable the slip driver on the comm port |
; slip removed |
|
not5: |
cmp eax, 6 |
jnz not6 |
|
; Insert an IP packet into the stacks received packet queue |
call stack_insert_packet |
ret |
|
not6: |
cmp eax, 7 |
jnz not7 |
|
; Test for any packets queued for transmission over the network |
|
not7: |
cmp eax, 8 |
jnz not8 |
|
call stack_get_packet |
; Extract a packet queued for transmission by the network |
ret |
|
not8: |
cmp eax, 9 |
jnz not9 |
|
; read the gateway IP address |
|
mov eax, [gateway_ip] |
ret |
|
not9: |
cmp eax, 10 |
jnz not10 |
|
; read the subnet mask |
|
mov eax, [subnet_mask] |
ret |
|
not10: |
cmp eax, 11 |
jnz not11 |
|
; write the gateway IP Address |
mov [gateway_ip], ebx |
|
ret |
|
not11: |
cmp eax, 12 |
jnz not12 |
|
; write the subnet mask |
mov [subnet_mask], ebx |
|
|
not12: |
cmp eax, 13 |
jnz not13 |
|
; read the dns |
|
mov eax, [dns_ip] |
ret |
|
not13: |
cmp eax, 14 |
jnz stack_driver_end |
|
; write the dns IP Address |
mov [dns_ip], ebx |
|
ret |
|
stack_driver_end: |
ret |
|
|
|
;*************************************************************************** |
; Function |
; app_socket_handler |
; |
; Description |
; This is an application service, called by int 0x40 |
; It provides application access to stack socket services |
; such as opening sockets |
; |
;*************************************************************************** |
app_socket_handler: |
cmp eax, 0 |
jnz nots0 |
|
call socket_open |
ret |
|
nots0: |
cmp eax, 1 |
jnz nots1 |
|
call socket_close |
ret |
|
nots1: |
cmp eax, 2 |
jnz nots2 |
|
call socket_poll |
ret |
|
nots2: |
cmp eax, 3 |
jnz nots3 |
|
call socket_read |
ret |
|
nots3: |
cmp eax, 4 |
jnz nots4 |
|
call socket_write |
ret |
|
nots4: |
cmp eax, 5 |
jnz nots5 |
|
call socket_open_tcp |
ret |
|
nots5: |
cmp eax, 6 |
jnz nots6 |
|
call socket_status |
ret |
|
nots6: |
cmp eax, 7 |
jnz nots7 |
|
call socket_write_tcp |
ret |
|
nots7: |
cmp eax, 8 |
jnz nots8 |
|
call socket_close_tcp |
ret |
|
nots8: |
cmp eax, 9 |
jnz nots9 |
|
call is_localport_unused |
ret |
|
nots9: |
cmp eax, 254 |
jnz notdump |
|
ret |
|
notdump: |
cmp eax, 255 |
jnz notsdebug |
|
; This sub function allows access to debugging information on the stack |
; ebx holds the request: |
; 100 : return length of empty queue |
; 101 : return length of IPOUT QUEUE |
; 102 : return length of IPIN QUEUE |
; 103 : return length of NET1OUT QUEUE |
; 200 : return # of ARP entries |
; 201 : return size of ARP table ( max # entries ) |
; 202 : select ARP table entry # |
; 203 : return IP of selected table entry |
; 204 : return High 4 bytes of MAC address of selected table entry |
; 205 : return low 2 bytes of MAC address of selected table entry |
; 206 : return status word of selected table entry |
; 207 : return Time to live of selected table entry |
|
|
; 2 : return number of IP packets received |
; 3 : return number of packets transmitted |
; 4 : return number of received packets dumped |
; 5 : return number of arp packets received |
; 6 : return status of packet driver |
; ( 0 == not active, FFFFFFFF = successful ) |
|
call stack_internal_status |
ret |
|
notsdebug: |
; Invalid Option |
ret |
|
|
uglobal |
ARPTmp: |
times 14 db 0 |
endg |
|
;*************************************************************************** |
; Function |
; stack_internal_status |
; |
; Description |
; Returns information about the internal status of the stack |
; This is only useful for debugging |
; It works with the ethernet driver |
; sub function in ebx |
; return requested data in eax |
; |
;*************************************************************************** |
stack_internal_status: |
cmp ebx, 100 |
jnz notsis100 |
|
; 100 : return length of EMPTY QUEUE |
mov ebx, EMPTY_QUEUE |
call queueSize |
ret |
|
notsis100: |
cmp ebx, 101 |
jnz notsis101 |
|
; 101 : return length of IPOUT QUEUE |
mov ebx, IPOUT_QUEUE |
call queueSize |
ret |
|
notsis101: |
cmp ebx, 102 |
jnz notsis102 |
|
; 102 : return length of IPIN QUEUE |
mov ebx, IPIN_QUEUE |
call queueSize |
ret |
|
notsis102: |
cmp ebx, 103 |
jnz notsis103 |
|
; 103 : return length of NET1OUT QUEUE |
mov ebx, NET1OUT_QUEUE |
call queueSize |
ret |
|
notsis103: |
cmp ebx, 200 |
jnz notsis200 |
|
; 200 : return num entries in arp table |
movzx eax, byte [NumARP] |
ret |
|
notsis200: |
cmp ebx, 201 |
jnz notsis201 |
|
; 201 : return arp table size |
mov eax, 20 ; ARP_TABLE_SIZE |
ret |
|
notsis201: |
cmp ebx, 202 |
jnz notsis202 |
|
; 202 - read the requested table entry |
; into a temporary buffer |
; ecx holds the entry number |
|
mov eax, ecx |
mov ecx, 14 ; ARP_ENTRY_SIZE |
mul ecx |
|
mov ecx, [eax + ARPTable] |
mov [ARPTmp], ecx |
mov ecx, [eax + ARPTable+4] |
mov [ARPTmp+4], ecx |
mov ecx, [eax + ARPTable+8] |
mov [ARPTmp+8], ecx |
mov cx, [eax + ARPTable+12] |
mov [ARPTmp+12], cx |
ret |
|
notsis202: |
cmp ebx, 203 |
jnz notsis203 |
|
; 203 - return IP address |
mov eax, [ARPTmp] |
ret |
|
notsis203: |
cmp ebx, 204 |
jnz notsis204 |
|
; 204 - return MAC high dword |
mov eax, [ARPTmp+4] |
ret |
|
notsis204: |
cmp ebx, 205 |
jnz notsis205 |
|
; 205 - return MAC ls word |
movzx eax, word [ARPTmp+8] |
ret |
|
notsis205: |
cmp ebx, 206 |
jnz notsis206 |
|
; 206 - return status word |
movzx eax, word [ARPTmp+10] |
ret |
|
notsis206: |
cmp ebx, 207 |
jnz notsis207 |
|
; 207 - return ttl word |
movzx eax, word [ARPTmp+12] |
ret |
|
notsis207: |
cmp ebx, 2 |
jnz notsis2 |
|
; 2 : return number of IP packets received |
mov eax, [ip_rx_count] |
ret |
|
notsis2: |
cmp ebx, 3 |
jnz notsis3 |
|
; 3 : return number of packets transmitted |
mov eax, [ip_tx_count] |
ret |
|
notsis3: |
cmp ebx, 4 |
jnz notsis4 |
|
; 4 : return number of received packets dumped |
mov eax, [dumped_rx_count] |
ret |
|
notsis4: |
cmp ebx, 5 |
jnz notsis5 |
|
; 5 : return number of arp packets received |
mov eax, [arp_rx_count] |
ret |
|
notsis5: |
cmp ebx, 6 |
jnz notsis6 |
|
; 6 : return status of packet driver |
; ( 0 == not active, FFFFFFFF = successful ) |
mov eax, [eth_status] |
ret |
|
notsis6: |
xor eax, eax |
ret |
|
|
|
;*************************************************************************** |
; Function |
; stack_get_packet |
; |
; Description |
; extracts an IP packet from the NET1 output queue |
; and sends the data to the calling process |
; pointer to data in edx |
; returns number of bytes read in eax |
; |
;*************************************************************************** |
stack_get_packet: |
; Look for a buffer to tx |
mov eax, NET1OUT_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
je sgp_non_exit ; Exit if no buffer available |
|
push eax ; Save buffer number for freeing at end |
|
push edx |
; convert buffer pointer eax to the absolute address |
mov ecx, IPBUFFSIZE |
mul ecx |
add eax, IPbuffs |
pop edx |
|
push eax ; save address of IP data |
|
; Get the address of the callers data |
mov edi,[0x3010] |
add edi,0x10 |
add edx,[edi] |
mov edi, edx |
|
pop eax |
|
mov ecx, 1500 ; should get the actual number of bytes to write |
mov esi, eax |
cld |
rep movsb ; copy the data across |
|
; And finally, return the buffer to the free queue |
pop eax |
call freeBuff |
|
mov eax, 1500 |
ret |
|
sgp_non_exit: |
xor eax, eax |
ret |
|
|
|
;*************************************************************************** |
; Function |
; stack_insert_packet |
; |
; Description |
; writes an IP packet into the stacks receive queue |
; # of bytes to write in ecx |
; pointer to data in edx |
; returns 0 in eax ok, -1 == failed |
; |
;*************************************************************************** |
stack_insert_packet: |
|
mov eax, EMPTY_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
je sip_err_exit |
|
push eax |
|
; save the pointers to the data buffer & size |
push edx |
push ecx |
|
; convert buffer pointer eax to the absolute address |
mov ecx, IPBUFFSIZE |
mul ecx |
add eax, IPbuffs |
|
mov edx, eax |
|
; So, edx holds the IPbuffer ptr |
|
pop ecx ; count of bytes to send |
mov ebx, ecx ; need the length later |
pop eax ; get callers ptr to data to send |
|
; Get the address of the callers data |
mov edi,[0x3010] |
add edi,0x10 |
add eax,[edi] |
mov esi, eax |
|
mov edi, edx |
cld |
rep movsb ; copy the data across |
|
pop ebx |
|
mov eax, IPIN_QUEUE |
call queue |
|
inc dword [ip_rx_count] |
|
mov eax, 0 |
ret |
|
sip_err_exit: |
mov eax, 0xFFFFFFFF |
ret |
|
|
|
;*************************************************************************** |
; Function |
; socket_open |
; |
; Description |
; find a free socket |
; local port in ebx |
; remote port in ecx |
; remote ip in edx |
; return socket # in eax, -1 if none available |
; |
;*************************************************************************** |
socket_open: |
call get_free_socket |
|
cmp eax, 0xFFFFFFFF |
jz so_exit |
|
; ax holds the socket number that is free. Get real address |
push eax |
shl eax, 12 |
add eax, sockets |
|
mov [eax], dword SOCK_OPEN |
|
mov [eax + 12], byte bh ; Local port ( LS 16 bits ) |
mov [eax + 13], byte bl ; Local port ( LS 16 bits ) |
mov ebx, [stack_ip] |
mov [eax + 8], ebx ; Local IP |
mov [eax + 20], ch ; Remote Port ( LS 16 bits ) |
mov [eax + 21], cl ; Remote Port ( LS 16 bits ) |
mov [eax + 16], edx ; Remote IP ( in Internet order ) |
mov [eax + 24], dword 0 ; recieved data count |
|
mov esi, [0x3010] |
mov ebx, [esi+0x4] |
mov [eax + 4], ebx ; save the process ID |
pop eax ; Get the socket number back, so we can return it |
|
so_exit: |
ret |
|
|
|
;*************************************************************************** |
; Function |
; socket_open_tcp |
; |
; Description |
; Opens a TCP socket in PASSIVE or ACTIVE mode |
; find a free socket |
; local port in ebx ( intel format ) |
; remote port in ecx ( intel format ) |
; remote ip in edx ( in Internet byte order ) |
; Socket open mode in esi ( SOCKET_PASSIVE or SOCKET_ACTIVE ) |
; return socket # in eax, -1 if none available |
; |
;*************************************************************************** |
socket_open_tcp: |
call get_free_socket |
|
cmp eax, 0xFFFFFFFF |
jz so_exit |
|
; ax holds the socket number that is free. Get real address |
push eax |
shl eax, 12 |
add eax, sockets |
|
mov [sktAddr], eax |
mov [eax], dword SOCK_OPEN |
|
; TODO - check this works! |
mov [eax + 72], dword 0 ; Reset the window timer. |
|
mov [eax + 12], byte bh ; Local port ( LS 16 bits ) |
mov [eax + 13], byte bl ; Local port ( LS 16 bits ) |
mov ebx, [stack_ip] |
mov [eax + 8], ebx ; Local IP |
mov [eax + 20], ch ; Remote Port ( LS 16 bits ) |
mov [eax + 21], cl ; Remote Port ( LS 16 bits ) |
mov [eax + 16], edx ; Remote IP ( in Internet order ) |
mov [eax + 24], dword 0 ; recieved data count |
|
; Now fill in TCB state |
mov ebx, TCB_LISTEN |
cmp esi, SOCKET_PASSIVE |
jz sot_001 |
mov ebx, TCB_SYN_SENT |
|
sot_001: |
mov [eax + 28], ebx ; Indicate the state of the TCB |
|
mov esi, [0x3010] |
mov ecx, [esi+0x4] |
mov [eax + 4], ecx ; save the process ID |
|
cmp ebx, TCB_LISTEN |
je sot_done |
|
; Now, if we are in active mode, then we have to send a SYN to the specified remote port |
|
|
mov eax, EMPTY_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
je sot_done |
|
push eax |
|
mov bl, 0x02 ; SYN |
mov ecx, 0 |
|
call buildTCPPacket |
|
mov eax, NET1OUT_QUEUE |
|
mov edx, [stack_ip] |
mov ecx, [ sktAddr ] |
mov ecx, [ ecx + 16 ] |
cmp edx, ecx |
jne sot_notlocal |
mov eax, IPIN_QUEUE |
|
sot_notlocal: |
; Send it. |
pop ebx |
call queue |
|
mov esi, [sktAddr] |
|
; increment SND.NXT in socket |
add esi, 48 |
call inc_inet_esi |
|
sot_done: |
pop eax ; Get the socket number back, so we can return it |
|
sot_exit: |
ret |
|
|
|
;*************************************************************************** |
; Function |
; socket_close |
; |
; Description |
; socket # in ebx |
; returns 0 for ok, -1 for socket not open (fail) |
; |
;*************************************************************************** |
socket_close: |
shl ebx, 12 |
add ebx, sockets |
mov eax, 0xFFFFFFFF ; assume this operation will fail.. |
cmp [ebx], dword SOCK_EMPTY |
jz sc_exit |
|
; Clear the socket varaibles |
xor eax, eax |
mov edi,ebx |
mov ecx,SOCKETHEADERSIZE |
cld |
rep stosb |
|
sc_exit: |
ret |
|
|
|
;*************************************************************************** |
; Function |
; socket_close_tcp |
; |
; Description |
; socket # in ebx |
; returns 0 for ok, -1 for socket not open (fail) |
; |
;*************************************************************************** |
socket_close_tcp: |
; first, remove any resend entries |
pusha |
|
mov esi, resendQ |
mov ecx, 0 |
|
sct001: |
cmp ecx, NUMRESENDENTRIES |
je sct003 ; None left |
cmp [esi], bl |
je sct002 ; found one |
inc ecx |
add esi, 4 |
jmp sct001 |
|
sct002: |
dec dword [arp_rx_count] ; ************ TEST ONLY! |
|
mov [esi], byte 0xFF |
jmp sct001 |
|
sct003: |
popa |
|
shl ebx, 12 |
add ebx, sockets |
mov [sktAddr], ebx |
mov eax, 0xFFFFFFFF ; assume this operation will fail.. |
cmp [ebx], dword SOCK_EMPTY |
jz sct_exit |
|
; Now construct the response, and queue for sending by IP |
mov eax, EMPTY_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
je stl_exit |
|
push eax |
|
mov bl, 0x11 ; FIN + ACK |
mov ecx, 0 |
mov esi, 0 |
|
call buildTCPPacket |
|
mov ebx, [sktAddr] |
|
; increament SND.NXT in socket |
mov esi, 48 |
add esi, ebx |
call inc_inet_esi |
|
|
; Get the socket state |
mov eax, [ebx + 28] |
cmp eax, TCB_LISTEN |
je destroyTCB |
cmp eax, TCB_SYN_SENT |
je destroyTCB |
cmp eax, TCB_SYN_RECEIVED |
je sct_finwait1 |
cmp eax, TCB_ESTABLISHED |
je sct_finwait1 |
|
; assume CLOSE WAIT |
; Send a fin, then enter last-ack state |
mov eax, TCB_LAST_ACK |
mov [ebx + 28], eax |
xor eax, eax |
jmp sct_send |
|
sct_finwait1: |
; Send a fin, then enter finwait2 state |
mov eax, TCB_FIN_WAIT_1 |
mov [ebx + 28], eax |
xor eax, eax |
|
sct_send: |
mov eax, NET1OUT_QUEUE |
|
mov edx, [stack_ip] |
mov ecx, [ sktAddr ] |
mov ecx, [ ecx + 16 ] |
cmp edx, ecx |
jne sct_notlocal |
mov eax, IPIN_QUEUE |
|
sct_notlocal: |
; Send it. |
pop ebx |
call queue |
jmp sct_exit |
|
destroyTCB: |
pop eax |
; Clear the socket varaibles |
xor eax, eax |
mov edi,ebx |
mov ecx,SOCKETHEADERSIZE |
cld |
rep stosb |
|
sct_exit: |
ret |
|
|
|
;*************************************************************************** |
; Function |
; socket_poll |
; |
; Description |
; socket # in ebx |
; returns count in eax. |
; |
;*************************************************************************** |
socket_poll: |
shl ebx, 12 |
add ebx, sockets |
mov eax, [ebx + 24] |
|
ret |
|
|
|
;*************************************************************************** |
; Function |
; socket_status |
; |
; Description |
; socket # in ebx |
; returns TCB state in eax. |
; |
;*************************************************************************** |
socket_status: |
shl ebx, 12 |
add ebx, sockets |
mov eax, [ebx + 28] |
|
ret |
|
|
|
;*************************************************************************** |
; Function |
; socket_read |
; |
; Description |
; socket # in ebx |
; returns # of bytes remaining in eax, data in bl |
; |
;*************************************************************************** |
socket_read: |
shl ebx, 12 |
add ebx, sockets |
mov eax, [ebx + 24] ; get count of bytes |
mov ecx,1 |
test eax, eax |
jz sr2 |
|
dec eax |
mov esi, ebx ; esi is address of socket |
mov [ebx + 24], eax ; store new count |
movzx ebx, byte [ebx + SOCKETHEADERSIZE] ; get the byte |
add esi, SOCKETHEADERSIZE |
mov edi, esi |
inc esi |
|
mov ecx, (SOCKETBUFFSIZE - SOCKETHEADERSIZE) / 4 |
cld |
rep movsd |
xor ecx, ecx |
|
sr1: |
jmp sor_exit |
|
sr2: |
xor bl, bl |
|
sor_exit: |
ret |
|
|
|
;*************************************************************************** |
; Function |
; socket_write |
; |
; Description |
; socket in ebx |
; # of bytes to write in ecx |
; pointer to data in edx |
; returns 0 in eax ok, -1 == failed ( invalid socket, or |
; could not queue IP packet ) |
; |
;*************************************************************************** |
socket_write: |
; First, find the address of the socket descriptor |
shl ebx, 12 |
add ebx, sockets ; ebx = address of actual socket |
|
mov eax, 0xFFFFFFFF |
; If the socket is invalid, return with an error code |
cmp [ebx], dword SOCK_EMPTY |
je sw_exit |
|
|
mov eax, EMPTY_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
je sw_exit |
|
; Save the queue entry number |
push eax |
|
; save the pointers to the data buffer & size |
push edx |
push ecx |
|
; convert buffer pointer eax to the absolute address |
mov ecx, IPBUFFSIZE |
mul ecx |
add eax, IPbuffs |
|
mov edx, eax |
|
; So, ebx holds the socket ptr, edx holds the IPbuffer ptr |
|
; Fill in the IP header ( some data is in the socket descriptor) |
mov eax, [ebx + 8] |
mov [edx + 12], eax ; source IP |
mov eax, [ebx + 16] |
mov [edx + 16], eax ; Destination IP |
|
mov al, 0x45 |
mov [edx], al ; Version, IHL |
xor al, al |
mov [edx + 1], al ; Type of service |
|
pop eax ; Get the UDP data length |
push eax |
|
add eax, 20 + 8 ; add IP header and UDP header lengths |
mov [edx + 2], ah |
mov [edx + 3], al |
xor al, al |
mov [edx + 4], al |
mov [edx + 5], al |
mov al, 0x40 |
mov [edx + 6], al |
xor al, al |
mov [edx + 7], al |
mov al, 0x20 |
mov [edx + 8], al |
mov al, 17 |
mov [edx + 9], al |
|
; Checksum left unfilled |
xor ax, ax |
mov [edx + 10], ax |
|
; Fill in the UDP header ( some data is in the socket descriptor) |
mov ax, [ebx + 12] |
mov [edx + 20], ax |
|
mov ax, [ebx + 20] |
mov [edx + 20 + 2], ax |
|
pop eax |
push eax |
|
add eax, 8 |
mov [edx + 20 + 4], ah |
mov [edx + 20 + 5], al |
|
; Checksum left unfilled |
xor ax, ax |
mov [edx + 20 + 6], ax |
|
pop ecx ; count of bytes to send |
mov ebx, ecx ; need the length later |
pop eax ; get callers ptr to data to send |
|
; Get the address of the callers data |
mov edi,[0x3010] |
add edi,0x10 |
add eax,[edi] |
mov esi, eax |
|
mov edi, edx |
add edi, 28 |
cld |
rep movsb ; copy the data across |
|
; we have edx as IPbuffer ptr. |
; Fill in the UDP checksum |
; First, fill in pseudoheader |
mov eax, [edx + 12] |
mov [pseudoHeader], eax |
mov eax, [edx + 16] |
mov [pseudoHeader+4], eax |
mov ax, 0x1100 ; 0 + protocol |
mov [pseudoHeader+8], ax |
add ebx, 8 |
mov eax, ebx |
mov [pseudoHeader+10], ah |
mov [pseudoHeader+11], al |
|
mov eax, pseudoHeader |
mov [checkAdd1], eax |
mov [checkSize1], word 12 |
mov eax, edx |
add eax, 20 |
mov [checkAdd2], eax |
mov eax, ebx |
mov [checkSize2], ax ; was eax!! mjh 8/7/02 |
|
call checksum |
|
; store it in the UDP checksum ( in the correct order! ) |
mov ax, [checkResult] |
|
; If the UDP checksum computes to 0, we must make it 0xffff |
; (0 is reserved for 'not used') |
cmp ax, 0 |
jne sw_001 |
mov ax, 0xffff |
|
sw_001: |
mov [edx + 20 + 6], ah |
mov [edx + 20 + 7], al |
|
; Fill in the IP header checksum |
mov eax, edx |
mov [checkAdd1], eax |
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 |
|
; Check destination IP address. |
; If it is the local host IP, route it back to IP_RX |
|
pop ebx |
mov eax, NET1OUT_QUEUE |
|
mov ecx, [ edx + 16] |
mov edx, [stack_ip] |
cmp edx, ecx |
jne sw_notlocal |
mov eax, IPIN_QUEUE |
|
sw_notlocal: |
; Send it. |
call queue |
|
xor eax, eax |
|
sw_exit: |
ret |
|
|
|
;*************************************************************************** |
; Function |
; socket_write_tcp |
; |
; Description |
; socket in ebx |
; # of bytes to write in ecx |
; pointer to data in edx |
; returns 0 in eax ok, -1 == failed ( invalid socket, or |
; could not queue IP packet ) |
; |
;*************************************************************************** |
socket_write_tcp: |
; First, find the address of the socket descriptor |
shl ebx, 12 |
add ebx, sockets ; ebx = address of actual socket |
|
mov [sktAddr], ebx |
|
mov eax, 0xFFFFFFFF |
; If the socket is invalid, return with an error code |
cmp [ebx], dword SOCK_EMPTY |
je swt_exit |
|
; If the sockets window timer is nonzero, do not queue packet |
; TODO - done |
cmp [ebx + 72], dword 0 |
jne swt_exit |
|
mov eax, EMPTY_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
je swt_exit |
|
push eax |
|
mov bl, 0x10 ; ACK |
|
; Get the address of the callers data |
mov edi,[0x3010] |
add edi,0x10 |
add edx,[edi] |
mov esi, edx |
|
pop eax |
push eax |
|
push ecx |
call buildTCPPacket |
pop ecx |
|
; Check destination IP address. |
; If it is the local host IP, route it back to IP_RX |
|
pop ebx |
push ecx |
mov eax, NET1OUT_QUEUE |
|
mov edx, [stack_ip] |
mov ecx, [ sktAddr ] |
mov ecx, [ ecx + 16 ] |
cmp edx, ecx |
jne swt_notlocal |
mov eax, IPIN_QUEUE |
|
swt_notlocal: |
pop ecx |
|
push ebx ; save ipbuffer number |
|
call queue |
|
mov esi, [sktAddr] |
|
; increament SND.NXT in socket |
; Amount to increment by is in ecx |
add esi, 48 |
call add_inet_esi |
|
pop ebx |
|
; Copy the IP buffer to a resend queue |
; If there isn't one, dont worry about it for now |
mov esi, resendQ |
mov ecx, 0 |
|
swt003: |
cmp ecx, NUMRESENDENTRIES |
je swt001 ; None found |
cmp [esi], byte 0xFF |
je swt002 ; found one |
inc ecx |
add esi, 4 |
jmp swt003 |
|
swt002: |
push ebx |
|
; OK, we have a buffer descriptor ptr in esi. |
; resend entry # in ecx |
; Populate it |
; socket # |
; retries count |
; retry time |
; fill IP buffer associated with this descriptor |
|
mov eax, [sktAddr] |
sub eax, sockets |
shr eax, 12 ; get skt # |
mov [esi], al |
mov [esi + 1], byte TCP_RETRIES |
mov [esi + 2], word TCP_TIMEOUT |
|
inc ecx |
; Now get buffer location, and copy buffer across. argh! more copying,, |
mov edi, resendBuffer - IPBUFFSIZE |
swt002a: |
add edi, IPBUFFSIZE |
loop swt002a |
|
; we have dest buffer location in edi |
pop eax |
; convert source buffer pointer eax to the absolute address |
mov ecx, IPBUFFSIZE |
mul ecx |
add eax, IPbuffs |
mov esi, eax |
|
; do copy |
mov ecx, IPBUFFSIZE |
cld |
rep movsb |
|
inc dword [arp_rx_count] ; ************ TEST ONLY! |
|
swt001: |
xor eax, eax |
|
swt_exit: |
ret |
|
|
|
; Below, the main network layer source code is included |
; |
|
include "queue.inc" |
include "ip.inc" |
include "tcp.inc" |
include "udp.inc" |
include "eth_drv/ethernet.inc" |