Subversion Repositories Kolibri OS

Rev

Rev 5363 | Rev 6011 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 5363 Rev 5522
1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                 ;;
2
;;                                                                 ;;
3
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved.    ;;
3
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved.    ;;
4
;; Distributed under terms of the GNU General Public License       ;;
4
;; Distributed under terms of the GNU General Public License       ;;
5
;;                                                                 ;;
5
;;                                                                 ;;
6
;;  ARP.INC                                                        ;;
6
;;  ARP.INC                                                        ;;
7
;;                                                                 ;;
7
;;                                                                 ;;
8
;;  Part of the tcp/ip network stack for KolibriOS                 ;;
8
;;  Part of the tcp/ip network stack for KolibriOS                 ;;
9
;;                                                                 ;;
9
;;                                                                 ;;
10
;;  Based on the work of [Johnny_B] and [smb]                      ;;
10
;;  Based on the work of [Johnny_B] and [smb]                      ;;
11
;;                                                                 ;;
11
;;                                                                 ;;
12
;;    Written by hidnplayr@kolibrios.org                           ;;
12
;;    Written by hidnplayr@kolibrios.org                           ;;
13
;;                                                                 ;;
13
;;                                                                 ;;
14
;;          GNU GENERAL PUBLIC LICENSE                             ;;
14
;;          GNU GENERAL PUBLIC LICENSE                             ;;
15
;;             Version 2, June- 1991                               ;;
15
;;             Version 2, June- 1991                               ;;
16
;;                                                                 ;;
16
;;                                                                 ;;
17
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
17
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
18
 
18
 
19
$Revision: 5363 $
19
$Revision: 5522 $
20
 
20
 
21
ARP_NO_ENTRY            = 0
21
ARP_NO_ENTRY            = 0
22
ARP_VALID_MAPPING       = 1
22
ARP_VALID_MAPPING       = 1
23
ARP_AWAITING_RESPONSE   = 2
23
ARP_AWAITING_RESPONSE   = 2
24
ARP_RESPONSE_TIMEOUT    = 3
24
ARP_RESPONSE_TIMEOUT    = 3
25
 
25
 
26
ARP_REQUEST_TTL         = 31          ; 20 s
26
ARP_REQUEST_TTL         = 31          ; 20 s
27
ARP_ENTRY_TTL           = 937         ; 600 s
27
ARP_ENTRY_TTL           = 937         ; 600 s
28
ARP_STATIC_ENTRY        = -1
28
ARP_STATIC_ENTRY        = -1
29
 
29
 
30
ARP_REQ_OPCODE          = 0x0100      ; request
30
ARP_REQ_OPCODE          = 0x0100      ; request
31
ARP_REP_OPCODE          = 0x0200      ; reply
31
ARP_REP_OPCODE          = 0x0200      ; reply
32
 
32
 
33
ARP_TABLE_SIZE          = 20          ; Size of table
33
ARP_TABLE_SIZE          = 20          ; Size of table
34
 
34
 
35
struct  ARP_entry
35
struct  ARP_entry
36
 
36
 
37
        IP              dd ?
37
        IP              dd ?
38
        MAC             dp ?
38
        MAC             dp ?
39
        Status          dw ?
39
        Status          dw ?
40
        TTL             dw ?
40
        TTL             dw ?
41
 
41
 
42
ends
42
ends
43
 
43
 
44
struct  ARP_header
44
struct  ARP_header
45
 
45
 
46
        HardwareType    dw ?
46
        HardwareType    dw ?
47
        ProtocolType    dw ?
47
        ProtocolType    dw ?
48
        HardwareSize    db ?
48
        HardwareSize    db ?
49
        ProtocolSize    db ?
49
        ProtocolSize    db ?
50
        Opcode          dw ?
50
        Opcode          dw ?
51
        SenderMAC       dp ?
51
        SenderMAC       dp ?
52
        SenderIP        dd ?
52
        SenderIP        dd ?
53
        TargetMAC       dp ?
53
        TargetMAC       dp ?
54
        TargetIP        dd ?
54
        TargetIP        dd ?
55
 
55
 
56
ends
56
ends
57
 
57
 
58
uglobal
58
uglobal
59
align 4
59
align 4
60
 
60
 
61
        ARP_table       rb NET_DEVICES_MAX*(ARP_TABLE_SIZE * sizeof.ARP_entry)
61
        ARP_table       rb NET_DEVICES_MAX*(ARP_TABLE_SIZE * sizeof.ARP_entry)
62
 
62
 
63
        ARP_entries_num rd NET_DEVICES_MAX
63
        ARP_entries_num rd NET_DEVICES_MAX
64
        ARP_PACKETS_TX  rd NET_DEVICES_MAX
64
        ARP_PACKETS_TX  rd NET_DEVICES_MAX
65
        ARP_PACKETS_RX  rd NET_DEVICES_MAX
65
        ARP_PACKETS_RX  rd NET_DEVICES_MAX
66
        ARP_CONFLICTS   rd NET_DEVICES_MAX
66
        ARP_CONFLICTS   rd NET_DEVICES_MAX
67
 
67
 
68
 
68
 
69
endg
69
endg
70
 
70
 
71
 
71
 
72
 
72
 
73
;-----------------------------------------------------------------
73
;-----------------------------------------------------------------
74
;
74
;
75
; ARP_init
75
; ARP_init
76
;
76
;
77
;  This function resets all ARP variables
77
;  This function resets all ARP variables
78
;
78
;
79
;-----------------------------------------------------------------
79
;-----------------------------------------------------------------
80
macro ARP_init {
80
macro ARP_init {
81
 
81
 
82
        xor     eax, eax
82
        xor     eax, eax
83
        mov     edi, ARP_entries_num
83
        mov     edi, ARP_entries_num
84
        mov     ecx, 4*NET_DEVICES_MAX
84
        mov     ecx, 4*NET_DEVICES_MAX
85
        rep stosd
85
        rep stosd
86
 
86
 
87
}
87
}
88
 
88
 
89
;---------------------------------------------------------------------------
89
;---------------------------------------------------------------------------
90
;
90
;
91
; ARP_decrease_entry_ttls
91
; ARP_decrease_entry_ttls
92
;
92
;
93
;---------------------------------------------------------------------------
93
;---------------------------------------------------------------------------
94
 
94
 
95
macro ARP_decrease_entry_ttls {
95
macro ARP_decrease_entry_ttls {
96
 
96
 
97
local   .loop
97
local   .loop
98
local   .exit
98
local   .exit
99
 
99
 
100
; The TTL field is decremented every second, and is deleted when it reaches 0.
100
; The TTL field is decremented every second, and is deleted when it reaches 0.
101
; It is refreshed every time a packet is received.
101
; It is refreshed every time a packet is received.
102
; If the TTL field is 0xFFFF it is a static entry and is never deleted.
102
; If the TTL field is 0xFFFF it is a static entry and is never deleted.
103
; The status field can be the following values:
103
; The status field can be the following values:
104
; 0x0000  entry not used
104
; 0x0000  entry not used
105
; 0x0001  entry holds a valid mapping
105
; 0x0001  entry holds a valid mapping
106
; 0x0002  entry contains an IP address, awaiting ARP response
106
; 0x0002  entry contains an IP address, awaiting ARP response
107
; 0x0003  No response received to ARP request.
107
; 0x0003  No response received to ARP request.
108
; The last status value is provided to allow the network layer to delete
108
; The last status value is provided to allow the network layer to delete
109
; a packet that is queued awaiting an ARP response
109
; a packet that is queued awaiting an ARP response
110
 
110
 
111
        xor     edi, edi
111
        xor     edi, edi
112
  .loop_outer:
112
  .loop_outer:
113
        mov     ecx, [ARP_entries_num + 4*edi]
113
        mov     ecx, [ARP_entries_num + 4*edi]
114
        test    ecx, ecx
114
        test    ecx, ecx
115
        jz      .exit
115
        jz      .exit
116
 
116
 
117
        mov     esi, (ARP_TABLE_SIZE * sizeof.ARP_entry)
117
        mov     esi, (ARP_TABLE_SIZE * sizeof.ARP_entry)
118
        imul    esi, edi
118
        imul    esi, edi
119
        add     esi, ARP_table
119
        add     esi, ARP_table
120
  .loop:
120
  .loop:
121
        cmp     [esi + ARP_entry.TTL], ARP_STATIC_ENTRY
121
        cmp     [esi + ARP_entry.TTL], ARP_STATIC_ENTRY
122
        je      .next
122
        je      .next
123
 
123
 
124
        dec     [esi + ARP_entry.TTL]
124
        dec     [esi + ARP_entry.TTL]
125
        jz      .time_out
125
        jz      .time_out
126
 
126
 
127
  .next:
127
  .next:
128
        add     esi, sizeof.ARP_entry
128
        add     esi, sizeof.ARP_entry
129
        dec     ecx
129
        dec     ecx
130
        jnz     .loop
130
        jnz     .loop
131
        jmp     .exit
131
        jmp     .exit
132
 
132
 
133
  .time_out:
133
  .time_out:
134
        cmp     [esi + ARP_entry.Status], ARP_AWAITING_RESPONSE
134
        cmp     [esi + ARP_entry.Status], ARP_AWAITING_RESPONSE
135
        je      .response_timeout
135
        je      .response_timeout
136
 
136
 
137
        push    esi edi ecx
137
        push    esi edi ecx
138
        call    ARP_del_entry
138
        call    ARP_del_entry
139
        pop     ecx edi esi
139
        pop     ecx edi esi
140
 
140
 
141
        jmp     .next
141
        jmp     .next
142
 
142
 
143
  .response_timeout:
143
  .response_timeout:
144
        mov     [esi + ARP_entry.Status], ARP_RESPONSE_TIMEOUT
144
        mov     [esi + ARP_entry.Status], ARP_RESPONSE_TIMEOUT
145
        mov     [esi + ARP_entry.TTL], 10
145
        mov     [esi + ARP_entry.TTL], 10
146
 
146
 
147
        jmp     .next
147
        jmp     .next
148
 
148
 
149
  .exit:
149
  .exit:
150
        inc     edi
150
        inc     edi
151
        cmp     edi, NET_DEVICES_MAX
151
        cmp     edi, NET_DEVICES_MAX
152
        jb      .loop_outer
152
        jb      .loop_outer
153
 
153
 
154
}
154
}
155
 
155
 
156
 
156
 
157
;-----------------------------------------------------------------
157
;-----------------------------------------------------------------
158
;
158
;
159
; ARP_input
159
; ARP_input
160
;
160
;
161
;  IN:  Pointer to buffer in [esp]
161
;  IN:  Pointer to buffer in [esp]
162
;       size of buffer in [esp+4]
162
;       size of buffer in [esp+4]
163
;       packet size (without ethernet header) in ecx
163
;       packet size (without ethernet header) in ecx
164
;       packet ptr in edx
164
;       packet ptr in edx
165
;       device ptr in ebx
165
;       device ptr in ebx
166
;  OUT: /
166
;  OUT: /
167
;
167
;
168
;-----------------------------------------------------------------
168
;-----------------------------------------------------------------
169
align 4
169
align 4
170
ARP_input:
170
ARP_input:
171
 
171
 
172
;-----------------------------------------
172
;-----------------------------------------
173
; Check validity and print some debug info
173
; Check validity and print some debug info
174
 
174
 
175
        cmp     ecx, sizeof.ARP_header
175
        cmp     ecx, sizeof.ARP_header
176
        jb      .exit
176
        jb      .exit
177
 
177
 
178
        call    NET_ptr_to_num4
178
        call    NET_ptr_to_num4
179
        cmp     edi, -1
179
        cmp     edi, -1
180
        jz      .exit
180
        jz      .exit
181
 
181
 
182
        inc     [ARP_PACKETS_RX + edi]          ; update stats
182
        inc     [ARP_PACKETS_RX + edi]          ; update stats
183
 
183
 
184
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: got packet from %u.%u.%u.%u (device*4=%u)\n",\
184
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: got packet from %u.%u.%u.%u (device*4=%u)\n",\
185
        [edx + ARP_header.SenderIP]:1, [edx + ARP_header.SenderIP + 1]:1,\
185
        [edx + ARP_header.SenderIP]:1, [edx + ARP_header.SenderIP + 1]:1,\
186
        [edx + ARP_header.SenderIP + 2]:1, [edx + ARP_header.SenderIP + 3]:1, edi
186
        [edx + ARP_header.SenderIP + 2]:1, [edx + ARP_header.SenderIP + 3]:1, edi
187
 
187
 
188
;------------------------------
188
;------------------------------
189
; First, check for IP collision
189
; First, check for IP collision
190
 
190
 
191
        mov     eax, [edx + ARP_header.SenderIP]
191
        mov     eax, [edx + ARP_header.SenderIP]
192
        cmp     eax, [IP_LIST + edi]
192
        cmp     eax, [IP_LIST + edi]
193
        je      .collision
193
        je      .collision
194
 
194
 
195
;---------------------
195
;---------------------
196
; Handle reply packets
196
; Handle reply packets
197
 
197
 
198
        cmp     [edx + ARP_header.Opcode], ARP_REP_OPCODE
198
        cmp     [edx + ARP_header.Opcode], ARP_REP_OPCODE
199
        jne     .maybe_request
199
        jne     .maybe_request
200
 
200
 
201
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: It's a reply\n"
201
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: It's a reply\n"
202
 
202
 
203
        mov     ecx, [ARP_entries_num + edi]
203
        mov     ecx, [ARP_entries_num + edi]
204
        test    ecx, ecx
204
        test    ecx, ecx
205
        jz      .exit
205
        jz      .exit
206
 
206
 
207
        mov     esi, edi
207
        mov     esi, edi
208
        imul    esi, (ARP_TABLE_SIZE * sizeof.ARP_entry)/4
208
        imul    esi, (ARP_TABLE_SIZE * sizeof.ARP_entry)/4
209
        add     esi, ARP_table
209
        add     esi, ARP_table
210
  .loop:
210
  .loop:
211
        cmp     [esi + ARP_entry.IP], eax
211
        cmp     [esi + ARP_entry.IP], eax
212
        je      .gotit
212
        je      .gotit
213
        add     esi, sizeof.ARP_entry
213
        add     esi, sizeof.ARP_entry
214
        dec     ecx
214
        dec     ecx
215
        jnz     .loop
215
        jnz     .loop
216
 
216
 
217
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: no matching entry found\n"
217
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: no matching entry found\n"
218
        jmp     .exit
218
        jmp     .exit
219
 
219
 
220
  .gotit:
220
  .gotit:
221
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: found matching entry\n"
221
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: found matching entry\n"
222
 
222
 
223
        cmp     [esi + ARP_entry.TTL], ARP_STATIC_ENTRY         ; if it is a static entry, dont touch it
223
        cmp     [esi + ARP_entry.TTL], ARP_STATIC_ENTRY         ; if it is a static entry, dont touch it
224
        je      .exit
224
        je      .exit
225
 
225
 
226
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: updating entry\n"
226
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: updating entry\n"
227
 
227
 
228
        mov     [esi + ARP_entry.Status], ARP_VALID_MAPPING
228
        mov     [esi + ARP_entry.Status], ARP_VALID_MAPPING
229
        mov     [esi + ARP_entry.TTL], ARP_ENTRY_TTL
229
        mov     [esi + ARP_entry.TTL], ARP_ENTRY_TTL
230
 
230
 
231
        mov     eax, dword [edx + ARP_header.SenderMAC]
231
        mov     eax, dword [edx + ARP_header.SenderMAC]
232
        mov     dword [esi + ARP_entry.MAC], eax
232
        mov     dword [esi + ARP_entry.MAC], eax
233
        mov     cx, word [edx + ARP_header.SenderMAC + 4]
233
        mov     cx, word [edx + ARP_header.SenderMAC + 4]
234
        mov     word [esi + ARP_entry.MAC + 4], cx
234
        mov     word [esi + ARP_entry.MAC + 4], cx
235
 
235
 
236
        jmp     .exit
236
        jmp     .exit
237
 
237
 
238
;-----------------------
238
;-----------------------
239
; Handle request packets
239
; Handle request packets
240
 
240
 
241
  .maybe_request:
241
  .maybe_request:
242
        cmp     [edx + ARP_header.Opcode], ARP_REQ_OPCODE
242
        cmp     [edx + ARP_header.Opcode], ARP_REQ_OPCODE
243
        jne     .exit
243
        jne     .exit
244
 
244
 
245
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: its a request\n"
245
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: its a request\n"
246
 
246
 
247
        mov     eax, [IP_LIST + edi]
247
        mov     eax, [IP_LIST + edi]
248
        cmp     eax, [edx + ARP_header.TargetIP]                ; Is it looking for my IP address?
248
        cmp     eax, [edx + ARP_header.TargetIP]                ; Is it looking for my IP address?
249
        jne     .exit
249
        jne     .exit
250
 
250
 
251
        push    eax
251
        push    eax
252
        push    edi
252
        push    edi
253
 
253
 
254
; OK, it is a request for one of our MAC addresses.
254
; OK, it is a request for one of our MAC addresses.
255
; Build the frame and send it. We can reuse the buffer.  (faster then using ARP_create_packet)
255
; Build the frame and send it. We can reuse the buffer.  (faster then using ARP_create_packet)
256
 
256
 
257
        lea     esi, [edx + ARP_header.SenderMAC]
257
        lea     esi, [edx + ARP_header.SenderMAC]
258
        lea     edi, [edx + ARP_header.TargetMAC]
258
        lea     edi, [edx + ARP_header.TargetMAC]
259
        movsd                                                   ; Move Sender Mac to Dest MAC
259
        movsd                                                   ; Move Sender Mac to Dest MAC
260
        movsw                                                   ;
260
        movsw                                                   ;
261
        movsd                                                   ; Move sender IP to Dest IP
261
        movsd                                                   ; Move sender IP to Dest IP
262
 
262
 
263
        pop     esi
263
        pop     esi
264
        mov     esi, [NET_DRV_LIST + esi]
264
        mov     esi, [NET_DRV_LIST + esi]
265
        lea     esi, [esi + ETH_DEVICE.mac]
265
        lea     esi, [esi + ETH_DEVICE.mac]
266
        lea     edi, [edx + ARP_header.SenderMAC]
266
        lea     edi, [edx + ARP_header.SenderMAC]
267
        movsd                                                   ; Copy MAC address from in MAC_LIST
267
        movsd                                                   ; Copy MAC address from in MAC_LIST
268
        movsw                                                   ;
268
        movsw                                                   ;
269
        pop     eax
269
        pop     eax
270
        stosd                                                   ; Write our IP
270
        stosd                                                   ; Write our IP
271
 
271
 
272
        mov     [edx + ARP_header.Opcode], ARP_REP_OPCODE
272
        mov     [edx + ARP_header.Opcode], ARP_REP_OPCODE
273
 
273
 
274
; Now, Fill in ETHERNET header
274
; Now, Fill in ETHERNET header
275
 
275
 
276
        mov     edi, [esp]
276
        mov     edi, [esp]
277
        lea     esi, [edx + ARP_header.TargetMAC]
277
        lea     esi, [edx + ARP_header.TargetMAC]
278
        movsd
278
        movsd
279
        movsw
279
        movsw
280
        lea     esi, [edx + ARP_header.SenderMAC]
280
        lea     esi, [edx + ARP_header.SenderMAC]
281
        movsd
281
        movsd
282
        movsw
282
        movsw
283
;        mov     ax , ETHER_ARP                                 ; It's already there, I'm sure of it!
283
;        mov     ax , ETHER_ARP                                 ; It's already there, I'm sure of it!
284
;        stosw
284
;        stosw
285
 
285
 
286
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: Sending reply\n"
286
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: Sending reply\n"
287
 
287
 
288
        call    [ebx + NET_DEVICE.transmit]
288
        call    [ebx + NET_DEVICE.transmit]
289
        ret
289
        ret
290
 
290
 
291
  .collision:
291
  .collision:
292
        inc     [ARP_CONFLICTS + edi]
292
        inc     [ARP_CONFLICTS + edi]
293
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: IP address conflict detected!\n"
293
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: IP address conflict detected!\n"
294
 
294
 
295
  .exit:
295
  .exit:
296
        call    NET_packet_free
-
 
297
        add     esp, 4                                          ; pop (balance stack)
-
 
298
 
-
 
299
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: exiting\n"
296
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: exiting\n"
-
 
297
        call    NET_BUFF_free
300
        ret
298
        ret
301
 
-
 
302
 
299
 
303
;---------------------------------------------------------------------------
300
;---------------------------------------------------------------------------
304
;
301
;
305
; ARP_output_request
302
; ARP_output_request
306
;
303
;
307
; IN:   ebx = device ptr
304
; IN:   ebx = device ptr
308
;       eax = IP
305
;       eax = IP
309
; OUT: /
306
; OUT: /
310
;       scratched: probably everything
307
;       scratched: probably everything
311
;
308
;
312
;---------------------------------------------------------------------------
309
;---------------------------------------------------------------------------
313
align 4
310
align 4
314
ARP_output_request:
311
ARP_output_request:
315
 
312
 
316
        push    eax
313
        push    eax
317
 
314
 
318
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_output_request: ip=%u.%u.%u.%u device=0x%x\n",\
315
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_output_request: ip=%u.%u.%u.%u device=0x%x\n",\
319
        [esp]:1, [esp + 1]:1, [esp + 2]:1, [esp + 3]:1, ebx
316
        [esp]:1, [esp + 1]:1, [esp + 2]:1, [esp + 3]:1, ebx
320
 
317
 
321
        mov     ax, ETHER_PROTO_ARP
318
        mov     ax, ETHER_PROTO_ARP
322
        mov     ecx, sizeof.ARP_header
319
        mov     ecx, sizeof.ARP_header
323
        mov     edx, ETH_BROADCAST              ; broadcast mac
320
        mov     edx, ETH_BROADCAST              ; broadcast mac
324
        call    ETH_output
321
        call    ETH_output
325
        jz      .exit
322
        jz      .exit
326
 
323
 
327
        mov     [edi + ARP_header.HardwareType], 0x0100         ; Ethernet
324
        mov     [edi + ARP_header.HardwareType], 0x0100         ; Ethernet
328
        mov     [edi + ARP_header.ProtocolType], 0x0008         ; IP
325
        mov     [edi + ARP_header.ProtocolType], 0x0008         ; IP
329
        mov     [edi + ARP_header.HardwareSize], 6              ; MAC-addr length
326
        mov     [edi + ARP_header.HardwareSize], 6              ; MAC-addr length
330
        mov     [edi + ARP_header.ProtocolSize], 4              ; IP-addr length
327
        mov     [edi + ARP_header.ProtocolSize], 4              ; IP-addr length
331
        mov     [edi + ARP_header.Opcode], ARP_REQ_OPCODE       ; Request
328
        mov     [edi + ARP_header.Opcode], ARP_REQ_OPCODE       ; Request
332
 
329
 
333
        add     edi, ARP_header.SenderMAC
330
        add     edi, ARP_header.SenderMAC
334
        lea     esi, [ebx + ETH_DEVICE.mac]     ; SenderMac
331
        lea     esi, [ebx + ETH_DEVICE.mac]     ; SenderMac
335
        movsw                                   ;
332
        movsw                                   ;
336
        movsd                                   ;
333
        movsd                                   ;
337
 
334
 
338
        push    edi
335
        push    edi
339
        call    NET_ptr_to_num4
336
        call    NET_ptr_to_num4
340
        inc     [ARP_PACKETS_TX + edi]          ; assume we will succeed
337
        inc     [ARP_PACKETS_TX + edi]          ; assume we will succeed
341
        lea     esi, [IP_LIST + edi]            ; SenderIP
338
        lea     esi, [IP_LIST + edi]            ; SenderIP
342
        pop     edi
339
        pop     edi
343
        movsd
340
        movsd
344
 
341
 
345
        mov     esi, ETH_BROADCAST              ; DestMac
342
        mov     esi, ETH_BROADCAST              ; DestMac
346
        movsw                                   ;
343
        movsw                                   ;
347
        movsd                                   ;
344
        movsd                                   ;
348
        popd    [edi]                           ; DestIP
345
        popd    [edi]                           ; DestIP
349
 
346
 
350
        push    edx eax
347
        push    eax
351
        call    [ebx + NET_DEVICE.transmit]
348
        call    [ebx + NET_DEVICE.transmit]
352
        ret
349
        ret
353
 
350
 
354
  .exit:
351
  .exit:
355
        add     esp, 4
352
        add     esp, 4
356
        DEBUGF  DEBUG_NETWORK_ERROR, "ARP_output_request: send failed\n"
353
        DEBUGF  DEBUG_NETWORK_ERROR, "ARP_output_request: send failed\n"
357
        ret
354
        ret
358
 
355
 
359
 
356
 
360
;-----------------------------------------------------------------
357
;-----------------------------------------------------------------
361
;
358
;
362
; ARP_add_entry (or update)
359
; ARP_add_entry (or update)
363
;
360
;
364
; IN:  esi = ptr to entry (can easily be made on the stack)
361
; IN:  esi = ptr to entry (can easily be made on the stack)
365
;      edi = device num*4
362
;      edi = device num*4
366
; OUT: eax = entry #, -1 on error
363
; OUT: eax = entry #, -1 on error
367
;      esi = ptr to newly created entry
364
;      esi = ptr to newly created entry
368
;
365
;
369
;-----------------------------------------------------------------      ; TODO: use a mutex
366
;-----------------------------------------------------------------      ; TODO: use a mutex
370
align 4
367
align 4
371
ARP_add_entry:
368
ARP_add_entry:
372
 
369
 
373
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_add_entry: device=%u\n", edi
370
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_add_entry: device=%u\n", edi
374
 
371
 
375
        mov     ecx, [ARP_entries_num + edi]
372
        mov     ecx, [ARP_entries_num + edi]
376
        cmp     ecx, ARP_TABLE_SIZE                                     ; list full ?
373
        cmp     ecx, ARP_TABLE_SIZE                                     ; list full ?
377
        jae     .full
374
        jae     .full
378
 
375
 
379
; From this point on, we can only fail if IP has a static entry, or if table is corrupt.
376
; From this point on, we can only fail if IP has a static entry, or if table is corrupt.
380
 
377
 
381
        inc     [ARP_entries_num + edi]                                 ; assume we will succeed
378
        inc     [ARP_entries_num + edi]                                 ; assume we will succeed
382
 
379
 
383
        push    edi
380
        push    edi
384
        xor     ecx, ecx
381
        xor     ecx, ecx
385
        imul    edi, ARP_TABLE_SIZE*sizeof.ARP_entry/4
382
        imul    edi, ARP_TABLE_SIZE*sizeof.ARP_entry/4
386
        add     edi, ARP_table
383
        add     edi, ARP_table
387
        mov     eax, [esi + ARP_entry.IP]
384
        mov     eax, [esi + ARP_entry.IP]
388
  .loop:
385
  .loop:
389
        cmp     [edi + ARP_entry.Status], ARP_NO_ENTRY                  ; is this slot empty?
386
        cmp     [edi + ARP_entry.Status], ARP_NO_ENTRY                  ; is this slot empty?
390
        je      .add
387
        je      .add
391
 
388
 
392
        cmp     [edi + ARP_entry.IP], eax                               ; if not, check if it doesnt collide
389
        cmp     [edi + ARP_entry.IP], eax                               ; if not, check if it doesnt collide
393
        jne     .maybe_next
390
        jne     .maybe_next
394
 
391
 
395
        cmp     [edi + ARP_entry.TTL], ARP_STATIC_ENTRY                 ; ok, its the same IP, update it if not static
392
        cmp     [edi + ARP_entry.TTL], ARP_STATIC_ENTRY                 ; ok, its the same IP, update it if not static
396
        jne     .add
393
        jne     .add
397
 
394
 
398
        DEBUGF  DEBUG_NETWORK_ERROR, "ARP_add_entry: failed, IP already has a static entry\n"
395
        DEBUGF  DEBUG_NETWORK_ERROR, "ARP_add_entry: failed, IP already has a static entry\n"
399
        jmp     .error
396
        jmp     .error
400
 
397
 
401
  .maybe_next:                                                          ; try the next slot
398
  .maybe_next:                                                          ; try the next slot
402
        add     edi, sizeof.ARP_entry
399
        add     edi, sizeof.ARP_entry
403
        inc     ecx
400
        inc     ecx
404
        cmp     ecx, ARP_TABLE_SIZE
401
        cmp     ecx, ARP_TABLE_SIZE
405
        jb      .loop
402
        jb      .loop
406
 
403
 
407
  .add:
404
  .add:
408
        push    ecx
405
        push    ecx
409
        mov     ecx, sizeof.ARP_entry/2
406
        mov     ecx, sizeof.ARP_entry/2
410
        rep movsw
407
        rep movsw
411
        pop     ecx
408
        pop     ecx
412
        lea     esi, [edi - sizeof.ARP_entry]
409
        lea     esi, [edi - sizeof.ARP_entry]
413
        pop     edi
410
        pop     edi
414
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_add_entry: entry=%u\n", ecx
411
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_add_entry: entry=%u\n", ecx
415
 
412
 
416
        ret
413
        ret
417
 
414
 
418
  .error:
415
  .error:
419
        pop     edi
416
        pop     edi
420
        dec     [ARP_entries_num + edi]
417
        dec     [ARP_entries_num + edi]
421
        DEBUGF  DEBUG_NETWORK_ERROR, "ARP_add_entry_failed\n"
418
        DEBUGF  DEBUG_NETWORK_ERROR, "ARP_add_entry_failed\n"
422
  .full:
419
  .full:
423
        mov     eax, -1
420
        mov     eax, -1
424
        ret
421
        ret
425
 
422
 
426
 
423
 
427
;-----------------------------------------------------------------
424
;-----------------------------------------------------------------
428
;
425
;
429
; ARP_del_entry
426
; ARP_del_entry
430
;
427
;
431
; IN:   esi = ptr to arp entry
428
; IN:   esi = ptr to arp entry
432
;       edi = device number
429
;       edi = device number
433
; OUT:  /
430
; OUT:  /
434
;
431
;
435
;-----------------------------------------------------------------
432
;-----------------------------------------------------------------
436
align 4
433
align 4
437
ARP_del_entry:
434
ARP_del_entry:
438
 
435
 
439
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_del_entry: entry=%x entrys=%u\n", esi, [ARP_entries_num + 4*edi]
436
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_del_entry: entry=%x entrys=%u\n", esi, [ARP_entries_num + 4*edi]
440
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_del_entry: IP=%u.%u.%u.%u\n", \
437
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_del_entry: IP=%u.%u.%u.%u\n", \
441
        [esi + ARP_entry.IP]:1, [esi + ARP_entry.IP + 1]:1, [esi + ARP_entry.IP + 2]:1, [esi + ARP_entry.IP + 3]:1
438
        [esi + ARP_entry.IP]:1, [esi + ARP_entry.IP + 1]:1, [esi + ARP_entry.IP + 2]:1, [esi + ARP_entry.IP + 3]:1
442
 
439
 
443
        push    edi
440
        push    edi
444
        imul    edi, (ARP_TABLE_SIZE) * sizeof.ARP_entry
441
        imul    edi, (ARP_TABLE_SIZE) * sizeof.ARP_entry
445
        lea     ecx, [ARP_table + (ARP_TABLE_SIZE - 1) * sizeof.ARP_entry + edi]
442
        lea     ecx, [ARP_table + (ARP_TABLE_SIZE - 1) * sizeof.ARP_entry + edi]
446
        sub     ecx, esi
443
        sub     ecx, esi
447
        shr     ecx, 1
444
        shr     ecx, 1
448
 
445
 
449
; move all trailing entries, sizeof.ARP_entry bytes to left.
446
; move all trailing entries, sizeof.ARP_entry bytes to left.
450
        mov     edi, esi
447
        mov     edi, esi
451
        add     esi, sizeof.ARP_entry
448
        add     esi, sizeof.ARP_entry
452
        rep movsw
449
        rep movsw
453
 
450
 
454
; now add an empty entry to the end (erasing previous one)
451
; now add an empty entry to the end (erasing previous one)
455
        xor     eax, eax
452
        xor     eax, eax
456
        mov     ecx, sizeof.ARP_entry/2
453
        mov     ecx, sizeof.ARP_entry/2
457
        rep stosw
454
        rep stosw
458
 
455
 
459
        pop     edi
456
        pop     edi
460
        dec     [ARP_entries_num + 4*edi]
457
        dec     [ARP_entries_num + 4*edi]
461
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_del_entry: success\n"
458
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_del_entry: success\n"
462
 
459
 
463
        ret
460
        ret
464
 
461
 
465
 
462
 
466
 
463
 
467
 
464
 
468
 
465
 
469
;-----------------------------------------------------------------
466
;-----------------------------------------------------------------
470
;
467
;
471
; ARP_IP_to_MAC
468
; ARP_IP_to_MAC
472
;
469
;
473
;  This function translates an IP address to a MAC address
470
;  This function translates an IP address to a MAC address
474
;
471
;
475
;  IN:  eax = IPv4 address
472
;  IN:  eax = IPv4 address
476
;       edi = device number * 4
473
;       edi = device number * 4
477
;  OUT: eax = -1 on error, -2 means request send
474
;  OUT: eax = -1 on error, -2 means request send
478
;      else, ax = first two bytes of mac (high 16 bits of eax will be 0)
475
;      else, ax = first two bytes of mac (high 16 bits of eax will be 0)
479
;       ebx = last four bytes of mac
476
;       ebx = last four bytes of mac
480
;       edi = unchanged
477
;       edi = unchanged
481
;
478
;
482
;-----------------------------------------------------------------
479
;-----------------------------------------------------------------
483
align 4
480
align 4
484
ARP_IP_to_MAC:
481
ARP_IP_to_MAC:
485
 
482
 
486
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: %u.%u", al, ah
483
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: %u.%u", al, ah
487
        rol     eax, 16
484
        rol     eax, 16
488
        DEBUGF  DEBUG_NETWORK_VERBOSE, ".%u.%u device*4: %u\n", al, ah, edi
485
        DEBUGF  DEBUG_NETWORK_VERBOSE, ".%u.%u device*4: %u\n", al, ah, edi
489
        rol     eax, 16
486
        rol     eax, 16
490
 
487
 
491
        cmp     eax, 0xffffffff
488
        cmp     eax, 0xffffffff
492
        je      .broadcast
489
        je      .broadcast
493
 
490
 
494
;--------------------------------
491
;--------------------------------
495
; Try to find the IP in ARP_table
492
; Try to find the IP in ARP_table
496
 
493
 
497
        mov     ecx, [ARP_entries_num + edi]
494
        mov     ecx, [ARP_entries_num + edi]
498
        test    ecx, ecx
495
        test    ecx, ecx
499
        jz      .not_in_list
496
        jz      .not_in_list
500
        mov     esi, edi
497
        mov     esi, edi
501
        imul    esi, (sizeof.ARP_entry * ARP_TABLE_SIZE)/4
498
        imul    esi, (sizeof.ARP_entry * ARP_TABLE_SIZE)/4
502
        add     esi, ARP_table + ARP_entry.IP
499
        add     esi, ARP_table + ARP_entry.IP
503
  .scan_loop:
500
  .scan_loop:
504
        cmp     [esi], eax
501
        cmp     [esi], eax
505
        je      .found_it
502
        je      .found_it
506
        add     esi, sizeof.ARP_entry
503
        add     esi, sizeof.ARP_entry
507
        dec     ecx
504
        dec     ecx
508
        jnz     .scan_loop
505
        jnz     .scan_loop
509
 
506
 
510
  .not_in_list:
507
  .not_in_list:
511
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: preparing for ARP request\n"
508
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: preparing for ARP request\n"
512
 
509
 
513
        push    eax edi                 ; save IP for ARP_output_request
510
        push    eax edi                 ; save IP for ARP_output_request
514
; Now craft the ARP entry on the stack
511
; Now craft the ARP entry on the stack
515
        pushw   ARP_REQUEST_TTL         ; TTL
512
        pushw   ARP_REQUEST_TTL         ; TTL
516
        pushw   ARP_AWAITING_RESPONSE   ; status
513
        pushw   ARP_AWAITING_RESPONSE   ; status
517
        pushd   0                       ; mac
514
        pushd   0                       ; mac
518
        pushw   0
515
        pushw   0
519
        pushd   eax                     ; ip
516
        pushd   eax                     ; ip
520
        mov     esi, esp
517
        mov     esi, esp
521
 
518
 
522
; Add it to the list
519
; Add it to the list
523
        call    ARP_add_entry
520
        call    ARP_add_entry
524
 
521
 
525
; Delete the temporary entry
522
; Delete the temporary entry
526
        add     esp, sizeof.ARP_entry   ; clear the entry from stack
523
        add     esp, sizeof.ARP_entry   ; clear the entry from stack
527
 
524
 
528
; If we could not add it to the list, give up
525
; If we could not add it to the list, give up
529
        cmp     eax, -1                 ; did ARP_add_entry fail?
526
        cmp     eax, -1                 ; did ARP_add_entry fail?
530
        je      .full
527
        je      .full
531
 
528
 
532
;-----------------------------------------------
529
;-----------------------------------------------
533
; At this point, we got an ARP entry in the list
530
; At this point, we got an ARP entry in the list
534
 
531
 
535
; Now send a request packet on the network
532
; Now send a request packet on the network
536
        pop     edi eax                 ; IP in eax, device number in ebx, for ARP_output_request
533
        pop     edi eax                 ; IP in eax, device number in ebx, for ARP_output_request
537
 
534
 
538
        push    esi edi
535
        push    esi edi
539
        mov     ebx, [NET_DRV_LIST + edi]
536
        mov     ebx, [NET_DRV_LIST + edi]
540
        call    ARP_output_request
537
        call    ARP_output_request
541
        pop     edi esi
538
        pop     edi esi
542
  .found_it:
539
  .found_it:
543
        cmp     [esi + ARP_entry.Status], ARP_VALID_MAPPING             ; Does it have a MAC assigned?
540
        cmp     [esi + ARP_entry.Status], ARP_VALID_MAPPING             ; Does it have a MAC assigned?
544
        je      .valid
541
        je      .valid
545
 
542
 
546
if ARP_BLOCK
543
if ARP_BLOCK
547
 
544
 
548
        cmp     [esi + ARP_entry.Status], ARP_AWAITING_RESPONSE         ; Are we waiting for reply from remote end?
545
        cmp     [esi + ARP_entry.Status], ARP_AWAITING_RESPONSE         ; Are we waiting for reply from remote end?
549
        jne     .give_up
546
        jne     .give_up
550
        push    esi
547
        push    esi
551
        mov     esi, 10                 ; wait 10 ms
548
        mov     esi, 10                 ; wait 10 ms
552
        call    delay_ms
549
        call    delay_ms
553
        pop     esi
550
        pop     esi
554
        jmp     .found_it               ; now check again
551
        jmp     .found_it               ; now check again
555
 
552
 
556
else
553
else
557
 
554
 
558
        jmp     .give_up
555
        jmp     .give_up
559
 
556
 
560
end if
557
end if
561
 
558
 
562
  .valid:
559
  .valid:
563
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: found MAC\n"
560
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: found MAC\n"
564
        movzx   eax, word[esi + ARP_entry.MAC]
561
        movzx   eax, word[esi + ARP_entry.MAC]
565
        mov     ebx, dword[esi + ARP_entry.MAC + 2]
562
        mov     ebx, dword[esi + ARP_entry.MAC + 2]
566
        ret
563
        ret
567
 
564
 
568
  .full:
565
  .full:
569
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: table is full!\n"
566
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: table is full!\n"
570
        add     esp, 8
567
        add     esp, 8
571
  .give_up:
568
  .give_up:
572
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: entry has no valid mapping!\n"
569
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: entry has no valid mapping!\n"
573
        mov     eax, -1
570
        mov     eax, -1
574
        ret
571
        ret
575
 
572
 
576
  .broadcast:
573
  .broadcast:
577
        mov     eax, 0x0000ffff
574
        mov     eax, 0x0000ffff
578
        mov     ebx, 0xffffffff
575
        mov     ebx, 0xffffffff
579
        ret
576
        ret
580
 
577
 
581
 
578
 
582
;-----------------------------------------------------------------
579
;-----------------------------------------------------------------
583
;
580
;
584
; ARP_API
581
; ARP_API
585
;
582
;
586
; This function is called by system function 76
583
; This function is called by system function 76
587
;
584
;
588
; IN:  subfunction number in bl
585
; IN:  subfunction number in bl
589
;      device number in bh
586
;      device number in bh
590
;      ecx, edx, .. depends on subfunction
587
;      ecx, edx, .. depends on subfunction
591
;
588
;
592
; OUT:  ?
589
; OUT:  ?
593
;
590
;
594
;-----------------------------------------------------------------
591
;-----------------------------------------------------------------
595
align 4
592
align 4
596
ARP_api:
593
ARP_api:
597
 
594
 
598
        movzx   eax, bh
595
        movzx   eax, bh
599
        shl     eax, 2
596
        shl     eax, 2
600
 
597
 
601
        and     ebx, 0xff
598
        and     ebx, 0xff
602
        cmp     ebx, .number
599
        cmp     ebx, .number
603
        ja      .error
600
        ja      .error
604
        jmp     dword [.table + 4*ebx]
601
        jmp     dword [.table + 4*ebx]
605
 
602
 
606
  .table:
603
  .table:
607
        dd      .packets_tx     ; 0
604
        dd      .packets_tx     ; 0
608
        dd      .packets_rx     ; 1
605
        dd      .packets_rx     ; 1
609
        dd      .entries        ; 2
606
        dd      .entries        ; 2
610
        dd      .read           ; 3
607
        dd      .read           ; 3
611
        dd      .write          ; 4
608
        dd      .write          ; 4
612
        dd      .remove         ; 5
609
        dd      .remove         ; 5
613
        dd      .send_announce  ; 6
610
        dd      .send_announce  ; 6
614
        dd      .conflicts      ; 7
611
        dd      .conflicts      ; 7
615
  .number = ($ - .table) / 4 - 1
612
  .number = ($ - .table) / 4 - 1
616
 
613
 
617
  .error:
614
  .error:
618
        mov     eax, -1
615
        mov     eax, -1
619
        ret
616
        ret
620
 
617
 
621
  .packets_tx:
618
  .packets_tx:
622
        mov     eax, [ARP_PACKETS_TX + eax]
619
        mov     eax, [ARP_PACKETS_TX + eax]
623
        ret
620
        ret
624
 
621
 
625
  .packets_rx:
622
  .packets_rx:
626
        mov     eax, [ARP_PACKETS_RX + eax]
623
        mov     eax, [ARP_PACKETS_RX + eax]
627
        ret
624
        ret
628
 
625
 
629
  .conflicts:
626
  .conflicts:
630
        mov     eax, [ARP_CONFLICTS + eax]
627
        mov     eax, [ARP_CONFLICTS + eax]
631
        ret
628
        ret
632
 
629
 
633
  .entries:
630
  .entries:
634
        mov     eax, [ARP_entries_num + eax]
631
        mov     eax, [ARP_entries_num + eax]
635
        ret
632
        ret
636
 
633
 
637
  .read:
634
  .read:
638
        cmp     ecx, [ARP_entries_num + eax]
635
        cmp     ecx, [ARP_entries_num + eax]
639
        jae     .error
636
        jae     .error
640
        shr     eax, 2
637
        shr     eax, 2
641
        imul    eax, sizeof.ARP_entry*ARP_TABLE_SIZE
638
        imul    eax, sizeof.ARP_entry*ARP_TABLE_SIZE
642
        add     eax, ARP_table
639
        add     eax, ARP_table
643
        ; edi = pointer to buffer
640
        ; edi = pointer to buffer
644
        ; ecx = # entry
641
        ; ecx = # entry
645
        imul    ecx, sizeof.ARP_entry
642
        imul    ecx, sizeof.ARP_entry
646
        lea     esi, [eax + ecx]
643
        lea     esi, [eax + ecx]
647
        mov     ecx, sizeof.ARP_entry/2
644
        mov     ecx, sizeof.ARP_entry/2
648
        rep movsw
645
        rep movsw
649
 
646
 
650
        xor     eax, eax
647
        xor     eax, eax
651
        ret
648
        ret
652
 
649
 
653
  .write:
650
  .write:
654
        ; esi = pointer to buffer
651
        ; esi = pointer to buffer
655
        mov     edi, eax
652
        mov     edi, eax
656
        call    ARP_add_entry           ; out: eax = entry number, -1 on error
653
        call    ARP_add_entry           ; out: eax = entry number, -1 on error
657
        ret
654
        ret
658
 
655
 
659
  .remove:
656
  .remove:
660
        ; ecx = # entry
657
        ; ecx = # entry
661
        cmp     ecx, [ARP_entries_num + eax]
658
        cmp     ecx, [ARP_entries_num + eax]
662
        jae     .error
659
        jae     .error
663
        imul    ecx, sizeof.ARP_entry
660
        imul    ecx, sizeof.ARP_entry
664
        lea     esi, [ARP_table + ecx]
661
        lea     esi, [ARP_table + ecx]
665
        mov     edi, eax
662
        mov     edi, eax
666
        shr     edi, 2
663
        shr     edi, 2
667
        call    ARP_del_entry
664
        call    ARP_del_entry
668
        ret
665
        ret
669
 
666
 
670
  .send_announce:
667
  .send_announce:
671
        mov     ebx, [NET_DRV_LIST + eax]
668
        mov     ebx, [NET_DRV_LIST + eax]
672
        mov     eax, [IP_LIST + eax]
669
        mov     eax, [IP_LIST + eax]
673
        call    ARP_output_request      ; now send a gratuitous ARP
670
        call    ARP_output_request      ; now send a gratuitous ARP
674
        ret
671
        ret