Subversion Repositories Kolibri OS

Rev

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

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