Subversion Repositories Kolibri OS

Rev

Rev 7682 | Details | Compare with Previous | Last modification | View Log | RSS feed

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