Subversion Repositories Kolibri OS

Rev

Rev 5584 | Rev 5976 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
3545 hidnplayr 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                 ;;
5363 yogev_ezra 3
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved.    ;;
3545 hidnplayr 4
;; Distributed under terms of the GNU General Public License       ;;
5
;;                                                                 ;;
6
;;  UDP.INC                                                        ;;
7
;;                                                                 ;;
8
;;  Part of the tcp/ip network stack for KolibriOS                 ;;
9
;;                                                                 ;;
10
;;    Written by hidnplayr@kolibrios.org                           ;;
11
;;                                                                 ;;
12
;;          GNU GENERAL PUBLIC LICENSE                             ;;
13
;;             Version 2, June 1991                                ;;
14
;;                                                                 ;;
15
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
16
 
4850 mario79 17
$Revision: 5842 $
3545 hidnplayr 18
 
19
 
20
struct  UDP_header
21
 
22
        SourcePort              dw  ?
23
        DestinationPort         dw  ?
24
        Length                  dw  ?  ; Length of (UDP Header + Data)
25
        Checksum                dw  ?
26
 
27
ends
28
 
29
 
3698 hidnplayr 30
uglobal
3545 hidnplayr 31
align 4
3698 hidnplayr 32
 
3600 hidnplayr 33
        UDP_PACKETS_TX          rd  NET_DEVICES_MAX
34
        UDP_PACKETS_RX          rd  NET_DEVICES_MAX
3698 hidnplayr 35
 
3545 hidnplayr 36
endg
37
 
38
 
39
;-----------------------------------------------------------------
40
;
41
; UDP_init
42
;
43
;  This function resets all UDP variables
44
;
45
;-----------------------------------------------------------------
46
macro   UDP_init {
47
 
48
        xor     eax, eax
49
        mov     edi, UDP_PACKETS_TX
3600 hidnplayr 50
        mov     ecx, 2*NET_DEVICES_MAX
3711 clevermous 51
        rep stosd
3545 hidnplayr 52
}
53
 
54
 
55
macro   UDP_checksum    IP1, IP2  { ; esi = ptr to udp packet, ecx = packet size, destroys: ecx, edx
56
 
57
; Pseudoheader
58
        mov     edx, IP_PROTO_UDP
59
 
5842 hidnplayr 60
        add     dl, byte[IP1+1]
61
        adc     dh, byte[IP1+0]
62
        adc     dl, byte[IP1+3]
63
        adc     dh, byte[IP1+2]
3545 hidnplayr 64
 
5842 hidnplayr 65
        adc     dl, byte[IP2+1]
66
        adc     dh, byte[IP2+0]
67
        adc     dl, byte[IP2+3]
68
        adc     dh, byte[IP2+2]
3545 hidnplayr 69
 
70
        adc     dl, cl ; byte[esi+UDP_header.Length+1]
71
        adc     dh, ch ; byte[esi+UDP_header.Length+0]
72
 
73
; Done with pseudoheader, now do real header
74
        adc     dl, byte[esi+UDP_header.SourcePort+1]
75
        adc     dh, byte[esi+UDP_header.SourcePort+0]
76
 
77
        adc     dl, byte[esi+UDP_header.DestinationPort+1]
78
        adc     dh, byte[esi+UDP_header.DestinationPort+0]
79
 
80
        adc     dl, byte[esi+UDP_header.Length+1]
81
        adc     dh, byte[esi+UDP_header.Length+0]
82
 
83
        adc     edx, 0
84
 
85
; Done with header, now do data
86
        push    esi
87
        movzx   ecx, [esi+UDP_header.Length]
88
        rol     cx , 8
89
        sub     cx , sizeof.UDP_header
90
        add     esi, sizeof.UDP_header
91
 
92
        call    checksum_1
93
        call    checksum_2
94
        pop     esi
95
 
96
        add     [esi+UDP_header.Checksum], dx   ; this final instruction will set or clear ZF :)
97
 
98
}
99
 
100
 
101
;-----------------------------------------------------------------
102
;
103
; UDP_input:
104
;
105
;  Called by IPv4_input,
5842 hidnplayr 106
;  this procedure will inject the UDP data in the application sockets.
3545 hidnplayr 107
;
5842 hidnplayr 108
;  IN:  [esp] = ptr to buffer
3545 hidnplayr 109
;       ebx = ptr to device struct
5842 hidnplayr 110
;       ecx = UDP packet size
111
;       edx = ptr to IPv4 header
112
;       esi = ptr to UDP packet data
113
;       edi = interface number*4
3545 hidnplayr 114
;
115
;  OUT: /
116
;
117
;-----------------------------------------------------------------
118
align 4
119
UDP_input:
120
 
3556 hidnplayr 121
        DEBUGF  DEBUG_NETWORK_VERBOSE, "UDP_input: size=%u\n", ecx
3545 hidnplayr 122
 
123
        ; First validate, checksum
124
 
125
        neg     [esi + UDP_header.Checksum]     ; substract checksum from 0
126
        jz      .no_checksum                    ; if checksum is zero, it is considered valid
127
 
128
        ; otherwise, we will re-calculate the checksum and add it to this value, thus creating 0 when it is correct
129
 
5842 hidnplayr 130
        mov     eax, edx
131
        UDP_checksum (eax+IPv4_header.SourceAddress), (eax+IPv4_header.DestinationAddress)
3545 hidnplayr 132
        jnz     .checksum_mismatch
133
 
134
  .no_checksum:
3556 hidnplayr 135
        DEBUGF  DEBUG_NETWORK_VERBOSE, "UDP_input: checksum ok\n"
3545 hidnplayr 136
 
137
        ; Convert length to little endian
138
 
139
        rol     [esi + UDP_header.Length], 8
140
 
141
        ; Look for a socket where
142
        ; IP Packet UDP Destination Port = local Port
143
        ; IP Packet SA = Remote IP
144
 
3647 hidnplayr 145
        pusha
146
        mov     ecx, socket_mutex
147
        call    mutex_lock
148
        popa
149
 
3545 hidnplayr 150
        mov     cx, [esi + UDP_header.SourcePort]
151
        mov     dx, [esi + UDP_header.DestinationPort]
152
        mov     eax, net_sockets
153
  .next_socket:
154
        mov     eax, [eax + SOCKET.NextPtr]
155
        or      eax, eax
5522 hidnplayr 156
        jz      .unlock_dump
3545 hidnplayr 157
 
158
        cmp     [eax + SOCKET.Domain], AF_INET4
159
        jne     .next_socket
160
 
161
        cmp     [eax + SOCKET.Protocol], IP_PROTO_UDP
162
        jne     .next_socket
163
 
164
        cmp     [eax + UDP_SOCKET.LocalPort], dx
165
        jne     .next_socket
166
 
3556 hidnplayr 167
        DEBUGF  DEBUG_NETWORK_VERBOSE, "UDP_input: socket=%x\n", eax
3545 hidnplayr 168
 
3647 hidnplayr 169
        pusha
170
        mov     ecx, socket_mutex
171
        call    mutex_unlock
172
        popa
173
 
5842 hidnplayr 174
        ;;; TODO: when packet is processed, check more sockets?!
3545 hidnplayr 175
 
5842 hidnplayr 176
; FIXME: check remote IP if possible
177
;
3545 hidnplayr 178
;        cmp     [eax + IP_SOCKET.RemoteIP], 0xffffffff
179
;        je      @f
5842 hidnplayr 180
;        cmp     [eax + IP_SOCKET.RemoteIP],
3545 hidnplayr 181
;        jne     .next_socket
182
;       @@:
183
 
4030 hidnplayr 184
        cmp     [eax + UDP_SOCKET.RemotePort], 0
3545 hidnplayr 185
        je      .updateport
186
 
187
        cmp     [eax + UDP_SOCKET.RemotePort], cx
188
        jne     .dump
189
 
190
        pusha
191
        lea     ecx, [eax + SOCKET.mutex]
192
        call    mutex_lock
193
        popa
194
 
195
  .updatesock:
3643 hidnplayr 196
        inc     [UDP_PACKETS_RX + edi]
3545 hidnplayr 197
 
198
        movzx   ecx, [esi + UDP_header.Length]
199
        sub     ecx, sizeof.UDP_header
200
        add     esi, sizeof.UDP_header
201
 
202
        jmp     SOCKET_input
203
 
204
  .updateport:
205
        pusha
206
        lea     ecx, [eax + SOCKET.mutex]
207
        call    mutex_lock
208
        popa
209
 
3556 hidnplayr 210
        DEBUGF  DEBUG_NETWORK_VERBOSE, "UDP_input: new remote port=%x\n", cx ; FIXME: find a way to print big endian values with debugf
3545 hidnplayr 211
        mov     [eax + UDP_SOCKET.RemotePort], cx
212
        jmp     .updatesock
213
 
5522 hidnplayr 214
  .unlock_dump:
3647 hidnplayr 215
        pusha
216
        mov     ecx, socket_mutex
217
        call    mutex_unlock
218
        popa
219
 
220
        DEBUGF  DEBUG_NETWORK_VERBOSE, "UDP_input: no socket found\n"
221
        jmp     .dump
222
 
3545 hidnplayr 223
  .checksum_mismatch:
3556 hidnplayr 224
        DEBUGF  DEBUG_NETWORK_VERBOSE, "UDP_input: checksum mismatch\n"
3545 hidnplayr 225
 
226
  .dump:
5522 hidnplayr 227
        DEBUGF  DEBUG_NETWORK_VERBOSE, "UDP_input: dumping\n"
228
        call    NET_BUFF_free
3545 hidnplayr 229
        ret
230
 
231
 
232
 
233
;-----------------------------------------------------------------
234
;
235
; UDP_output
236
;
237
; IN: eax = socket pointer
238
;     ecx = number of bytes to send
239
;     esi = pointer to data
240
;
5015 hidnplayr 241
; OUT: eax = -1 on error
242
;
3545 hidnplayr 243
;-----------------------------------------------------------------
244
 
245
align 4
246
UDP_output:
247
 
3556 hidnplayr 248
        DEBUGF  DEBUG_NETWORK_VERBOSE, "UDP_output: socket=%x bytes=%u data_ptr=%x\n", eax, ecx, esi
3545 hidnplayr 249
 
250
        mov     dx, [eax + UDP_SOCKET.RemotePort]
3556 hidnplayr 251
        DEBUGF  DEBUG_NETWORK_VERBOSE, "UDP_output: remote port=%x, ", dx    ; FIXME: find a way to print big endian values with debugf
3545 hidnplayr 252
        rol     edx, 16
253
        mov     dx, [eax + UDP_SOCKET.LocalPort]
3556 hidnplayr 254
        DEBUGF  DEBUG_NETWORK_VERBOSE, "local port=%x\n", dx
3545 hidnplayr 255
 
5522 hidnplayr 256
        sub     esp, 4                                          ; Data ptr will be placed here
3545 hidnplayr 257
        push    edx esi
5842 hidnplayr 258
        mov     ebx, [eax + IP_SOCKET.device]
3545 hidnplayr 259
        mov     edx, [eax + IP_SOCKET.LocalIP]
5842 hidnplayr 260
        mov     edi, [eax + IP_SOCKET.RemoteIP]
261
        mov     al, [eax + IP_SOCKET.ttl]
262
        mov     ah, IP_PROTO_UDP
3545 hidnplayr 263
        add     ecx, sizeof.UDP_header
264
        call    IPv4_output
265
        jz      .fail
266
        mov     [esp + 8], eax                                  ; pointer to buffer start
267
 
268
        mov     [edi + UDP_header.Length], cx
269
        rol     [edi + UDP_header.Length], 8
270
 
271
        pop     esi
272
        push    edi ecx
273
        sub     ecx, sizeof.UDP_header
274
        add     edi, sizeof.UDP_header
275
        shr     ecx, 2
3711 clevermous 276
        rep movsd
3545 hidnplayr 277
        mov     ecx, [esp]
278
        and     ecx, 3
3711 clevermous 279
        rep movsb
3545 hidnplayr 280
        pop     ecx edi
281
 
282
        pop     dword [edi + UDP_header.SourcePort]
283
 
284
; Checksum
285
        mov     esi, edi
286
        mov     [edi + UDP_header.Checksum], 0
287
        UDP_checksum (edi-4), (edi-8)                           ; FIXME: IPv4 packet could have options..
288
 
3556 hidnplayr 289
        DEBUGF  DEBUG_NETWORK_VERBOSE, "UDP_output: sending with device %x\n", ebx
3545 hidnplayr 290
        call    [ebx + NET_DEVICE.transmit]
291
        test    eax, eax
292
        jnz     @f
3643 hidnplayr 293
        call    NET_ptr_to_num4
294
        inc     [UDP_PACKETS_TX + edi]
3545 hidnplayr 295
       @@:
296
 
297
        ret
298
 
299
  .fail:
3556 hidnplayr 300
        DEBUGF  DEBUG_NETWORK_ERROR, "UDP_output: failed\n"
3545 hidnplayr 301
        add     esp, 4+4+8
302
        or      eax, -1
303
        ret
304
 
305
 
306
 
4030 hidnplayr 307
 
308
;-----------------------------------------------------------------
309
;
310
; UDP_connect
311
;
312
;   IN: eax = socket pointer
313
;  OUT: eax = 0 ok / -1 error
314
;       ebx = error code
315
;
316
;-------------------------
317
align 4
318
UDP_connect:
319
 
320
        test    [eax + SOCKET.state], SS_ISCONNECTED
321
        jz      @f
322
        call    UDP_disconnect
323
  @@:
324
 
4035 hidnplayr 325
        push    eax edx
4030 hidnplayr 326
        lea     ecx, [eax + SOCKET.mutex]
327
        call    mutex_lock
4035 hidnplayr 328
        pop     edx eax
4030 hidnplayr 329
 
330
; Fill in local IP
331
        cmp     [eax + IP_SOCKET.LocalIP], 0
332
        jne     @f
333
        push    [IP_LIST + 4]                                   ; FIXME: use correct local IP
334
        pop     [eax + IP_SOCKET.LocalIP]
335
 
336
; Fill in remote port and IP, overwriting eventually previous values
337
        pushw   [edx + 2]
338
        pop     [eax + UDP_SOCKET.RemotePort]
339
 
340
        pushd   [edx + 4]
341
        pop     [eax + IP_SOCKET.RemoteIP]
342
 
343
; Find a local port, if user didnt define one
344
        cmp     [eax + UDP_SOCKET.LocalPort], 0
345
        jne     @f
346
        call    SOCKET_find_port
347
       @@:
348
 
349
        push    eax
350
        lea     ecx, [eax + SOCKET.mutex]
351
        call    mutex_unlock
352
        pop     eax
353
 
354
        call    SOCKET_is_connected
355
 
356
        xor     eax, eax
357
        ret
358
 
359
 
360
;-----------------------------------------------------------------
361
;
362
; UDP_disconnect
363
;
364
;   IN: eax = socket pointer
365
;  OUT: eax = socket pointer
366
;
367
;-------------------------
368
align 4
369
UDP_disconnect:
370
 
371
        ; TODO: remove the pending received data
372
 
373
        call    SOCKET_is_disconnected
374
 
375
        ret
376
 
377
 
378
 
379
 
380
 
3545 hidnplayr 381
;---------------------------------------------------------------------------
382
;
383
; UDP_API
384
;
385
; This function is called by system function 75
386
;
387
; IN:  subfunction number in bl
388
;      device number in bh
389
;      ecx, edx, .. depends on subfunction
390
;
391
; OUT:
392
;
393
;---------------------------------------------------------------------------
394
 
395
align 4
396
UDP_api:
397
 
398
        movzx   eax, bh
399
        shl     eax, 2
400
 
401
        test    bl, bl
402
        jz      .packets_tx     ; 0
403
        dec     bl
404
        jz      .packets_rx     ; 1
405
 
406
  .error:
407
        mov     eax, -1
408
        ret
409
 
410
  .packets_tx:
411
        mov     eax, [UDP_PACKETS_TX + eax]
412
        ret
413
 
414
  .packets_rx:
415
        mov     eax, [UDP_PACKETS_RX + eax]
416
        ret