Subversion Repositories Kolibri OS

Rev

Rev 7679 | Go to most recent revision | 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: 7682 $
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                                      ;
308
;                                                                 ;
309
;  OUT: eax = 0 on success                                        ;
310
;       eax = -1 on error                                         ;
311
;       ebx = error code on error                                 ;
312
;                                                                 ;
313
;-----------------------------------------------------------------;
4030 hidnplayr 314
align 4
6011 hidnplayr 315
udp_connect:
4030 hidnplayr 316
 
317
        test    [eax + SOCKET.state], SS_ISCONNECTED
318
        jz      @f
6011 hidnplayr 319
        call    udp_disconnect
4030 hidnplayr 320
  @@:
321
 
4035 hidnplayr 322
        push    eax edx
4030 hidnplayr 323
        lea     ecx, [eax + SOCKET.mutex]
324
        call    mutex_lock
4035 hidnplayr 325
        pop     edx eax
4030 hidnplayr 326
 
6911 hidnplayr 327
; Fill in remote port and IP
4030 hidnplayr 328
        pushw   [edx + 2]
329
        pop     [eax + UDP_SOCKET.RemotePort]
330
 
331
        pushd   [edx + 4]
6911 hidnplayr 332
        pop     [eax + UDP_SOCKET.RemoteIP]
4030 hidnplayr 333
 
6911 hidnplayr 334
; Find route to host
335
        pusha
336
        push    eax
337
        mov     ebx, [eax + UDP_SOCKET.device]
338
        mov     edx, [eax + UDP_SOCKET.LocalIP]
339
        mov     eax, [eax + UDP_SOCKET.RemoteIP]
340
        call    ipv4_route
341
        test    eax, eax
342
        jz      .enoroute
343
        pop     eax
7679 hidnplayr 344
        mov     ebx, [net_device_list + edi]
6911 hidnplayr 345
        mov     [eax + UDP_SOCKET.device], ebx
346
        mov     [eax + UDP_SOCKET.LocalIP], edx
347
        popa
348
 
4030 hidnplayr 349
; Find a local port, if user didnt define one
350
        cmp     [eax + UDP_SOCKET.LocalPort], 0
351
        jne     @f
6011 hidnplayr 352
        call    socket_find_port
4030 hidnplayr 353
       @@:
354
 
355
        push    eax
356
        lea     ecx, [eax + SOCKET.mutex]
357
        call    mutex_unlock
358
        pop     eax
359
 
6011 hidnplayr 360
        call    socket_is_connected
4030 hidnplayr 361
 
362
        xor     eax, eax
363
        ret
364
 
6911 hidnplayr 365
  .enoroute:
366
        pop     eax
7682 hidnplayr 367
 
368
        push    eax
369
        lea     ecx, [eax + SOCKET.mutex]
370
        call    mutex_unlock
371
        pop     eax
372
 
6911 hidnplayr 373
        popa
374
        xor     eax, eax
375
        dec     eax
376
        mov     ebx, EADDRNOTAVAIL
377
        ret
4030 hidnplayr 378
 
6911 hidnplayr 379
 
5976 hidnplayr 380
;-----------------------------------------------------------------;
381
;                                                                 ;
382
; UDP_disconnect                                                  ;
383
;                                                                 ;
384
;   IN: eax = socket pointer                                      ;
385
;                                                                 ;
386
;  OUT: eax = socket pointer                                      ;
387
;                                                                 ;
388
;-----------------------------------------------------------------;
4030 hidnplayr 389
align 4
6011 hidnplayr 390
udp_disconnect:
4030 hidnplayr 391
 
392
        ; TODO: remove the pending received data
393
 
6011 hidnplayr 394
        call    socket_is_disconnected
4030 hidnplayr 395
 
396
        ret
397
 
398
 
399
 
400
 
401
 
5976 hidnplayr 402
;-----------------------------------------------------------------;
403
;                                                                 ;
6011 hidnplayr 404
; UDP_api: Part of system function 76                             ;
5976 hidnplayr 405
;                                                                 ;
406
;  IN: bl = subfunction number in bl                              ;
407
;      bh = device number in bh                                   ;
408
;      ecx, edx, .. depends on subfunction                        ;
409
;                                                                 ;
410
; OUT: depends on subfunction                                     ;
411
;                                                                 ;
412
;-----------------------------------------------------------------;
3545 hidnplayr 413
align 4
6011 hidnplayr 414
udp_api:
3545 hidnplayr 415
 
416
        movzx   eax, bh
417
        shl     eax, 2
418
 
419
        test    bl, bl
420
        jz      .packets_tx     ; 0
421
        dec     bl
422
        jz      .packets_rx     ; 1
423
 
424
  .error:
425
        mov     eax, -1
426
        ret
427
 
428
  .packets_tx:
7678 hidnplayr 429
        mov     eax, [UDP_packets_tx + eax]
3545 hidnplayr 430
        ret
431
 
432
  .packets_rx:
7678 hidnplayr 433
        mov     eax, [UDP_packets_rx + eax]
3545 hidnplayr 434
        ret