Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
3545 hidnplayr 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                 ;;
3
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved.    ;;
4
;; Distributed under terms of the GNU General Public License       ;;
5
;;                                                                 ;;
6
;;  Part of the TCP/IP network stack for KolibriOS                 ;;
7
;;                                                                 ;;
8
;;   Written by hidnplayr@kolibrios.org,                           ;;
9
;;     and Clevermouse.                                            ;;
10
;;                                                                 ;;
11
;;       Based on code by mike.dld                                 ;;
12
;;                                                                 ;;
13
;;         GNU GENERAL PUBLIC LICENSE                              ;;
14
;;          Version 2, June 1991                                   ;;
15
;;                                                                 ;;
16
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
17
 
18
$Revision: 3514 $
19
 
3658 hidnplayr 20
ENOBUFS         = 1
21
EOPNOTSUPP      = 4
22
EWOULDBLOCK     = 6
23
ENOTCONN        = 9
24
EALREADY        = 10
25
EINVAL          = 11
26
EMSGSIZE        = 12
27
ENOMEM          = 18
28
EADDRINUSE      = 20
3545 hidnplayr 29
 
3658 hidnplayr 30
 
3545 hidnplayr 31
struct  SOCKET
32
 
33
        NextPtr                 dd ? ; pointer to next socket in list
34
        PrevPtr                 dd ? ; pointer to previous socket in list
35
        Number                  dd ? ; socket number
36
 
37
        mutex                   MUTEX
38
 
39
        PID                     dd ? ; process ID
40
        TID                     dd ? ; thread ID
41
        Domain                  dd ? ; INET/LOCAL/..
42
        Type                    dd ? ; RAW/STREAM/DGRAP
43
        Protocol                dd ? ; ICMP/IPv4/ARP/TCP/UDP
44
        errorcode               dd ?
45
        device                  dd ? ; driver pointer, socket pointer if it's an LOCAL socket
46
 
47
        options                 dd ?
48
        state                   dd ?
49
        backlog                 dw ? ; how many incoming connections that can be queued
50
 
51
        snd_proc                dd ?
52
        rcv_proc                dd ?
53
 
54
ends
55
 
56
struct  IP_SOCKET               SOCKET
57
 
58
        LocalIP                 rd 4 ; network byte order
59
        RemoteIP                rd 4 ; network byte order
60
 
61
ends
62
 
63
struct  TCP_SOCKET              IP_SOCKET
64
 
65
        LocalPort               dw ? ; network byte order
66
        RemotePort              dw ? ; network byte order
67
 
68
        t_state                 dd ? ; TCB state
69
        t_rxtshift              db ?
70
                                rb 3 ; align
71
        t_rxtcur                dd ?
72
        t_dupacks               dd ?
73
        t_maxseg                dd ?
74
        t_force                 dd ?
75
        t_flags                 dd ?
76
 
77
;---------------
78
; RFC783 page 21
79
 
80
; send sequence
81
        SND_UNA                 dd ? ; sequence number of unack'ed sent Packets
82
        SND_NXT                 dd ? ; next send sequence number to use
83
        SND_UP                  dd ? ; urgent pointer
84
        SND_WL1                 dd ? ; window minus one
85
        SND_WL2                 dd ? ;
86
        ISS                     dd ? ; initial send sequence number
87
        SND_WND                 dd ? ; send window
88
 
89
; receive sequence
90
        RCV_WND                 dd ? ; receive window
91
        RCV_NXT                 dd ? ; next receive sequence number to use
92
        RCV_UP                  dd ? ; urgent pointer
93
        IRS                     dd ? ; initial receive sequence number
94
 
95
;---------------------
96
; Additional variables
97
 
98
; receive variables
99
        RCV_ADV                 dd ?
100
 
101
; retransmit variables
102
        SND_MAX                 dd ?
103
 
104
; congestion control
105
        SND_CWND                dd ?
106
        SND_SSTHRESH            dd ?
107
 
108
;----------------------
109
; Transmit timing stuff
110
        t_idle                  dd ?
111
        t_rtt                   dd ?
112
        t_rtseq                 dd ?
113
        t_srtt                  dd ?
114
        t_rttvar                dd ?
115
        t_rttmin                dd ?
116
        max_sndwnd              dd ?
117
 
118
;-----------------
119
; Out-of-band data
120
        t_oobflags              dd ?
121
        t_iobc                  dd ?
122
        t_softerror             dd ?
123
 
124
 
125
;---------
126
; RFC 1323                              ; the order of next 4 elements may not change
127
 
128
        SND_SCALE               db ?
129
        RCV_SCALE               db ?
130
        requested_s_scale       db ?
131
        request_r_scale         db ?
132
 
133
        ts_recent               dd ?    ; a copy of the most-recent valid timestamp from the other end
134
        ts_recent_age           dd ?
135
        last_ack_sent           dd ?
136
 
137
 
138
;-------
139
; Timers
3600 hidnplayr 140
        timer_flags             dd ?
3545 hidnplayr 141
        timer_retransmission    dd ? ; rexmt
142
        timer_persist           dd ?
143
        timer_keepalive         dd ? ; keepalive/syn timeout
144
        timer_timed_wait        dd ? ; also used as 2msl timer
145
 
146
; extra
147
 
148
        ts_ecr                  dd ? ; timestamp echo reply
149
        ts_val                  dd ?
150
 
151
        seg_next                dd ? ; re-assembly queue
152
 
153
        temp_bits               db ?
154
                                rb 3 ; align
155
 
156
ends
157
 
158
struct  UDP_SOCKET              IP_SOCKET
159
 
160
        LocalPort               dw ? ; network byte order
161
        RemotePort              dw ? ; network byte order
162
        firstpacket             db ?
163
 
164
ends
165
 
166
 
167
struct  ICMP_SOCKET             IP_SOCKET
168
 
169
        Identifier              dw ?
170
 
171
ends
172
 
173
 
174
struct  RING_BUFFER
175
 
176
        mutex                   MUTEX
177
        start_ptr               dd ? ; Pointer to start of buffer
178
        end_ptr                 dd ? ; pointer to end of buffer
179
        read_ptr                dd ? ; Read pointer
180
        write_ptr               dd ? ; Write pointer
181
        size                    dd ? ; Number of bytes buffered
182
 
183
ends
184
 
185
struct  STREAM_SOCKET           TCP_SOCKET
186
 
187
        rcv                     RING_BUFFER
188
        snd                     RING_BUFFER
189
 
190
ends
191
 
192
struct  socket_queue_entry
193
 
194
        data_ptr                dd ?
195
        buf_ptr                 dd ?
196
        data_size               dd ?
197
 
198
ends
199
 
200
 
201
SOCKETBUFFSIZE          = 4096     ; in bytes
202
 
203
SOCKET_QUEUE_SIZE       = 10       ; maximum number of incoming packets queued for 1 socket
204
; the incoming packet queue for sockets is placed in the socket struct itself, at this location from start
205
SOCKET_QUEUE_LOCATION   = (SOCKETBUFFSIZE - SOCKET_QUEUE_SIZE*sizeof.socket_queue_entry - sizeof.queue)
206
 
207
uglobal
208
        net_sockets     rd 4
209
        last_socket_num dd ?
210
        last_UDP_port   dw ? ; These values give the number of the last used ephemeral port
211
        last_TCP_port   dw ? ;
3647 hidnplayr 212
        socket_mutex    MUTEX
3545 hidnplayr 213
endg
214
 
215
 
216
;-----------------------------------------------------------------
217
;
218
; SOCKET_init
219
;
220
;-----------------------------------------------------------------
221
macro   SOCKET_init {
222
 
223
        xor     eax, eax
224
        mov     edi, net_sockets
225
        mov     ecx, 5
226
        rep     stosd
227
 
228
       @@:
229
        pseudo_random eax
3600 hidnplayr 230
        cmp     ax, EPHEMERAL_PORT_MIN
3545 hidnplayr 231
        jb      @r
3600 hidnplayr 232
        cmp     ax, EPHEMERAL_PORT_MAX
3545 hidnplayr 233
        ja      @r
234
        xchg    al, ah
235
        mov     [last_UDP_port], ax
236
 
237
       @@:
238
        pseudo_random eax
3600 hidnplayr 239
        cmp     ax, EPHEMERAL_PORT_MIN
3545 hidnplayr 240
        jb      @r
3600 hidnplayr 241
        cmp     ax, EPHEMERAL_PORT_MAX
3545 hidnplayr 242
        ja      @r
243
        xchg    al, ah
244
        mov     [last_TCP_port], ax
245
 
3647 hidnplayr 246
        mov     ecx, socket_mutex
247
        call    mutex_init
248
 
3545 hidnplayr 249
}
250
 
251
;-----------------------------------------------------------------
252
;
253
; Socket API (function 74)
254
;
255
;-----------------------------------------------------------------
256
align 4
257
sys_socket:
258
 
259
        cmp     ebx, 255
260
        jz      SOCKET_debug
261
 
262
        cmp     ebx, .number
3658 hidnplayr 263
        ja      .error
3545 hidnplayr 264
        jmp     dword [.table + 4*ebx]
265
 
266
  .table:
267
        dd      SOCKET_open     ; 0
268
        dd      SOCKET_close    ; 1
269
        dd      SOCKET_bind     ; 2
270
        dd      SOCKET_listen   ; 3
271
        dd      SOCKET_connect  ; 4
272
        dd      SOCKET_accept   ; 5
273
        dd      SOCKET_send     ; 6
274
        dd      SOCKET_receive  ; 7
275
        dd      SOCKET_set_opt  ; 8
276
        dd      SOCKET_get_opt  ; 9
277
        dd      SOCKET_pair     ; 10
278
  .number = ($ - .table) / 4 - 1
279
 
3658 hidnplayr 280
  .error:
281
        mov     dword[esp+32], -1
282
        mov     dword[esp+24], EINVAL
3545 hidnplayr 283
 
284
        ret
285
 
286
;-----------------------------------------------------------------
287
;
288
; SOCKET_open
289
;
290
;  IN:  domain in ecx
291
;       type in edx
292
;       protocol in esi
293
;  OUT: eax is socket num, -1 on error
294
;
295
;-----------------------------------------------------------------
296
align 4
297
SOCKET_open:
298
 
3556 hidnplayr 299
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_open: domain=%u type=%u protocol=%x ", ecx, edx, esi
3545 hidnplayr 300
 
301
        push    ecx edx esi
302
        call    SOCKET_alloc
303
        pop     esi edx ecx
3658 hidnplayr 304
        jz      .nobuffs
3545 hidnplayr 305
 
306
        mov     [esp+32], edi                   ; return socketnumber
3556 hidnplayr 307
        DEBUGF  DEBUG_NETWORK_VERBOSE, "socknum=%u\n", edi
3545 hidnplayr 308
 
309
;        push    edx
310
;        and     edx, SO_NONBLOCK
311
        or      [eax + SOCKET.options], SO_NONBLOCK ;edx
312
;        pop     edx
313
;        and     edx, not SO_NONBLOCK
314
 
315
        mov     [eax + SOCKET.Domain], ecx
316
        mov     [eax + SOCKET.Type], edx
317
        mov     [eax + SOCKET.Protocol], esi
318
 
319
        cmp     ecx, AF_INET4
320
        jne     .no_inet4
321
 
322
        cmp     edx, SOCK_DGRAM
323
        je      .udp
324
 
325
        cmp     edx, SOCK_STREAM
326
        je      .tcp
327
 
328
        cmp     edx, SOCK_RAW
329
        je      .raw
330
 
331
  .no_inet4:
332
        cmp     ecx, AF_PPP
333
        jne     .no_ppp
334
 
335
        cmp     esi, PPP_PROTO_ETHERNET
336
        je      .pppoe
337
 
338
  .no_ppp:
3658 hidnplayr 339
  .unsupported:
340
        push    eax
341
        call    SOCKET_free
342
        pop     eax
343
        mov     dword[esp+24], EOPNOTSUPP
344
        mov     dword[esp+32], -1
3545 hidnplayr 345
        ret
346
 
3658 hidnplayr 347
  .nobuffs:
348
        mov     dword[esp+24], ENOBUFS
349
        mov     dword[esp+32], -1
350
        ret
351
 
3545 hidnplayr 352
  .raw:
353
        test    esi, esi       ; IP_PROTO_IP
3658 hidnplayr 354
        jz      .raw_ip
3545 hidnplayr 355
 
356
        cmp     esi, IP_PROTO_ICMP
3658 hidnplayr 357
        je      .raw_icmp
3545 hidnplayr 358
 
3658 hidnplayr 359
        jmp     .unsupported
3545 hidnplayr 360
 
361
align 4
362
  .udp:
363
        mov     [eax + SOCKET.Protocol], IP_PROTO_UDP
364
        mov     [eax + SOCKET.snd_proc], SOCKET_send_udp
365
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_dgram
366
        ret
367
 
368
align 4
369
  .tcp:
370
        mov     [eax + SOCKET.Protocol], IP_PROTO_TCP
371
        mov     [eax + SOCKET.snd_proc], SOCKET_send_tcp
372
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_stream
373
 
374
        TCP_init_socket eax
375
        ret
376
 
377
 
378
align 4
3658 hidnplayr 379
  .raw_ip:
3545 hidnplayr 380
        mov     [eax + SOCKET.snd_proc], SOCKET_send_ip
381
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_dgram
382
        ret
383
 
384
 
385
align 4
3658 hidnplayr 386
  .raw_icmp:
3545 hidnplayr 387
        mov     [eax + SOCKET.snd_proc], SOCKET_send_icmp
388
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_dgram
389
        ret
390
 
391
align 4
392
  .pppoe:
393
        push    eax
394
        init_queue (eax + SOCKET_QUEUE_LOCATION)        ; Set up data receiving queue
395
        pop     eax
396
 
397
        mov     [eax + SOCKET.snd_proc], SOCKET_send_pppoe
398
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_dgram
399
        ret
400
 
401
 
402
;-----------------------------------------------------------------
403
;
404
; SOCKET_bind
405
;
406
;  IN:  socket number in ecx
407
;       pointer to sockaddr struct in edx
408
;       length of that struct in esi
409
;  OUT: 0 on success
410
;
411
;-----------------------------------------------------------------
412
align 4
413
SOCKET_bind:
414
 
3556 hidnplayr 415
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_bind: socknum=%u sockaddr=%x length=%u\n", ecx, edx, esi
3545 hidnplayr 416
 
417
        call    SOCKET_num_to_ptr
3658 hidnplayr 418
        jz      .invalid
3545 hidnplayr 419
 
420
        cmp     esi, 2
3658 hidnplayr 421
        jb      .invalid
3545 hidnplayr 422
 
423
        cmp     word [edx], AF_INET4
424
        je      .af_inet4
425
 
426
        cmp     word [edx], AF_LOCAL
427
        je      .af_local
428
 
3658 hidnplayr 429
  .notsupp:
430
        mov     dword[esp+24], EOPNOTSUPP
431
        mov     dword[esp+32], -1
432
        ret
3545 hidnplayr 433
 
3658 hidnplayr 434
  .invalid:
435
        mov     dword[esp+24], EINVAL
436
        mov     dword[esp+32], -1
437
        ret
438
 
3545 hidnplayr 439
  .af_local:
440
        ; TODO: write code here
3658 hidnplayr 441
        mov     dword[esp+32], 0
3545 hidnplayr 442
        ret
443
 
444
  .af_inet4:
445
        cmp     esi, 6
3658 hidnplayr 446
        jb      .invalid
3545 hidnplayr 447
 
448
        cmp     [eax + SOCKET.Protocol], IP_PROTO_UDP
449
        je      .udp
450
 
451
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
452
        je      .tcp
453
 
3658 hidnplayr 454
        jmp     .notsupp
3545 hidnplayr 455
 
456
  .tcp:
457
  .udp:
3637 hidnplayr 458
        mov     ebx, [edx + 4]                  ; First, fill in the IP
3545 hidnplayr 459
        test    ebx, ebx                        ; If IP is 0, use default
460
        jnz     @f
3601 hidnplayr 461
        mov     ebx, [IP_LIST + 4]      ;;;;; FIXME !i!i!i
3545 hidnplayr 462
       @@:
463
        mov     [eax + IP_SOCKET.LocalIP], ebx
464
 
465
        mov     bx, [edx + 2]                   ; Now fill in the local port if it's still available
466
        call    SOCKET_check_port
3658 hidnplayr 467
        jz      .addrinuse                      ; ZF is set by socket_check_port, on error
3545 hidnplayr 468
 
3556 hidnplayr 469
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_bind: local ip=%u.%u.%u.%u\n",\
3545 hidnplayr 470
        [eax + IP_SOCKET.LocalIP + 0]:1,[eax + IP_SOCKET.LocalIP + 1]:1,\
471
        [eax + IP_SOCKET.LocalIP + 2]:1,[eax + IP_SOCKET.LocalIP + 3]:1
472
 
3658 hidnplayr 473
        mov     dword[esp+32], 0
3545 hidnplayr 474
        ret
475
 
3658 hidnplayr 476
  .addrinuse:
477
        mov     dword[esp+32], -1
478
        mov     dword[esp+24], EADDRINUSE
479
        ret
3545 hidnplayr 480
 
481
 
482
 
3658 hidnplayr 483
 
3545 hidnplayr 484
;-----------------------------------------------------------------
485
;
486
; SOCKET_connect
487
;
488
;  IN:  socket number in ecx
489
;       pointer to sockaddr struct in edx
490
;       length of that struct in esi
491
;  OUT: 0 on success
492
;
493
;-----------------------------------------------------------------
494
align 4
495
SOCKET_connect:
496
 
3556 hidnplayr 497
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_connect: socknum=%u sockaddr=%x length=%u\n", ecx, edx, esi
3545 hidnplayr 498
 
499
        call    SOCKET_num_to_ptr
3658 hidnplayr 500
        jz      .invalid
3545 hidnplayr 501
 
502
        cmp     esi, 8
3658 hidnplayr 503
        jb      .invalid
3545 hidnplayr 504
 
505
        cmp     word [edx], AF_INET4
506
        je      .af_inet4
507
 
3658 hidnplayr 508
  .notsupp:
509
        mov     dword[esp+24], EOPNOTSUPP
510
        mov     dword[esp+32], -1
511
        ret
3545 hidnplayr 512
 
3658 hidnplayr 513
  .invalid:
514
        mov     dword[esp+24], EINVAL
515
        mov     dword[esp+32], -1
516
        ret
517
 
3545 hidnplayr 518
  .af_inet4:
519
        cmp     [eax + IP_SOCKET.LocalIP], 0
520
        jne     @f
3601 hidnplayr 521
        push    [IP_LIST + 4]                               ; FIXME !i!i!i!
3545 hidnplayr 522
        pop     [eax + IP_SOCKET.LocalIP]
523
       @@:
524
 
525
        cmp     [eax + SOCKET.Protocol], IP_PROTO_UDP
526
        je      .udp
527
 
528
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
529
        je      .tcp
530
 
531
        cmp     [eax + SOCKET.Protocol], IP_PROTO_IP
532
        je      .ip
533
 
534
        cmp     [eax + SOCKET.Protocol], IP_PROTO_ICMP
535
        je      .ip
536
 
3658 hidnplayr 537
        jmp     .notsupp
3545 hidnplayr 538
 
539
align 4
540
  .udp:
541
        pusha
542
        lea     ecx, [eax + SOCKET.mutex]
543
        call    mutex_lock
544
        popa
545
 
546
        pushw   [edx + 2]
547
        pop     [eax + UDP_SOCKET.RemotePort]
548
 
549
        pushd   [edx + 4]
550
        pop     [eax + IP_SOCKET.RemoteIP]
551
 
552
        cmp     [eax + UDP_SOCKET.LocalPort], 0
553
        jne     @f
554
        call    SOCKET_find_port
555
       @@:
556
 
557
        mov     [eax + UDP_SOCKET.firstpacket], 0
558
 
559
        push    eax
560
        init_queue (eax + SOCKET_QUEUE_LOCATION)        ; Set up data receiving queue
561
        pop     eax
562
 
563
        lea     ecx, [eax + SOCKET.mutex]
564
        call    mutex_unlock
565
 
3658 hidnplayr 566
        mov     dword[esp+32], 0
3545 hidnplayr 567
        ret
568
 
569
align 4
570
  .tcp:
571
        pusha
572
        lea     ecx, [eax + SOCKET.mutex]
573
        call    mutex_lock
574
        popa
575
 
576
        pushw   [edx + 2]
577
        pop     [eax + TCP_SOCKET.RemotePort]
578
 
579
        pushd   [edx + 4]
580
        pop     [eax + IP_SOCKET.RemoteIP]
581
 
582
        cmp     [eax + TCP_SOCKET.LocalPort], 0
583
        jne     @f
584
        call    SOCKET_find_port
585
       @@:
586
 
587
        mov     [eax + TCP_SOCKET.timer_persist], 0
588
        mov     [eax + TCP_SOCKET.t_state], TCPS_SYN_SENT
589
 
590
        push    [TCP_sequence_num]
591
        add     [TCP_sequence_num], 6400
592
        pop     [eax + TCP_SOCKET.ISS]
593
        mov     [eax + TCP_SOCKET.timer_keepalive], TCP_time_keep_init
594
 
595
 
596
        TCP_sendseqinit eax
597
 
598
;        mov     [ebx + TCP_SOCKET.timer_retransmission],   ;; todo: create macro to set retransmission timer
599
 
600
        mov     ebx, eax
601
 
602
        lea     eax, [ebx + STREAM_SOCKET.snd]
3658 hidnplayr 603
        call    SOCKET_ring_create              ; TODO: check if memory was available or not
3545 hidnplayr 604
 
605
        lea     eax, [ebx + STREAM_SOCKET.rcv]
3658 hidnplayr 606
        call    SOCKET_ring_create              ; TODO: same here
3545 hidnplayr 607
 
608
        pusha
609
        lea     ecx, [ebx + SOCKET.mutex]
610
        call    mutex_unlock
611
        popa
612
 
613
        mov     eax, ebx
614
        call    TCP_output
615
 
616
;;; TODO: wait for successfull connection if blocking socket
617
 
3658 hidnplayr 618
        mov     dword[esp+32], 0
3545 hidnplayr 619
        ret
620
 
621
align 4
622
  .ip:
623
        pusha
624
        lea     ecx, [eax + SOCKET.mutex]
625
        call    mutex_lock
626
        popa
627
 
628
        pushd   [edx + 4]
629
        pop     [eax + IP_SOCKET.RemoteIP]
630
 
631
        push    eax
632
        init_queue (eax + SOCKET_QUEUE_LOCATION)        ; Set up data receiving queue
633
        pop     eax
634
 
635
        lea     ecx, [eax + SOCKET.mutex]
636
        call    mutex_unlock
637
 
3658 hidnplayr 638
        mov     dword[esp+32], 0
3545 hidnplayr 639
        ret
640
 
641
 
642
;-----------------------------------------------------------------
643
;
644
; SOCKET_listen
645
;
646
;  IN:  socket number in ecx
647
;       backlog in edx
648
;  OUT: eax is socket num, -1 on error
649
;
650
;-----------------------------------------------------------------
651
align 4
652
SOCKET_listen:
653
 
3556 hidnplayr 654
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_listen: socknum=%u backlog=%u\n", ecx, edx
3545 hidnplayr 655
 
656
        call    SOCKET_num_to_ptr
3658 hidnplayr 657
        jz      .invalid
3545 hidnplayr 658
 
659
        cmp     [eax + SOCKET.Domain], AF_INET4
3658 hidnplayr 660
        jne     .notsupp
3545 hidnplayr 661
 
662
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
3658 hidnplayr 663
        jne     .invalid
3545 hidnplayr 664
 
665
        cmp     [eax + TCP_SOCKET.LocalPort], 0
3658 hidnplayr 666
        je      .already
3545 hidnplayr 667
 
668
        cmp     [eax + IP_SOCKET.LocalIP], 0
669
        jne     @f
3601 hidnplayr 670
        push    [IP_LIST + 4]           ;;; fixme!!!!
3545 hidnplayr 671
        pop     [eax + IP_SOCKET.LocalIP]
672
       @@:
673
 
674
        cmp     edx, MAX_backlog
675
        jbe     @f
676
        mov     edx, MAX_backlog
677
       @@:
678
 
679
        mov     [eax + SOCKET.backlog], dx
680
        or      [eax + SOCKET.options], SO_ACCEPTCON
681
        mov     [eax + TCP_SOCKET.t_state], TCPS_LISTEN
682
        mov     [eax + TCP_SOCKET.timer_keepalive], 0           ; disable keepalive timer
683
 
684
        push    eax
685
        init_queue (eax + SOCKET_QUEUE_LOCATION)                ; Set up sockets queue
686
        pop     eax
687
 
3658 hidnplayr 688
        mov     dword[esp+32], 0
689
        ret
3545 hidnplayr 690
 
3658 hidnplayr 691
  .notsupp:
692
        mov     dword[esp+24], EOPNOTSUPP
693
        mov     dword[esp+32], -1
3545 hidnplayr 694
        ret
695
 
3658 hidnplayr 696
  .invalid:
697
        mov     dword[esp+24], EINVAL
698
        mov     dword[esp+32], -1
699
        ret
3545 hidnplayr 700
 
3658 hidnplayr 701
  .already:
702
        mov     dword[esp+24], EALREADY
703
        mov     dword[esp+32], -1
704
        ret
705
 
706
 
3545 hidnplayr 707
;-----------------------------------------------------------------
708
;
709
; SOCKET_accept
710
;
711
;  IN:  socket number in ecx
712
;       addr in edx
713
;       addrlen in esi
714
;  OUT: eax is socket num, -1 on error
715
;
716
;-----------------------------------------------------------------
717
align 4
718
SOCKET_accept:
719
 
3556 hidnplayr 720
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_accept: socknum=%u sockaddr=%x length=%u\n", ecx, edx, esi
3545 hidnplayr 721
 
722
        call    SOCKET_num_to_ptr
3658 hidnplayr 723
        jz      .invalid
3545 hidnplayr 724
 
725
        test    [eax + SOCKET.options], SO_ACCEPTCON
3658 hidnplayr 726
        jz      .invalid
3545 hidnplayr 727
 
728
        cmp     [eax + SOCKET.Domain], AF_INET4
3658 hidnplayr 729
        jne     .notsupp
3545 hidnplayr 730
 
731
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
3658 hidnplayr 732
        jne     .invalid
3545 hidnplayr 733
 
734
  .loop:
735
        get_from_queue (eax + SOCKET_QUEUE_LOCATION), MAX_backlog, 4, .block
736
 
737
; Ok, we got a socket ptr
738
        mov     eax, [esi]
739
 
3658 hidnplayr 740
; Convert it to a socket number
741
        call    SOCKET_ptr_to_num
742
        jz      .invalid        ; FIXME ?
743
 
3545 hidnplayr 744
; Change thread ID to that of the current thread
745
        mov     ebx, [TASK_BASE]
746
        mov     ebx, [ebx + TASKDATA.pid]
747
        mov     [eax + SOCKET.TID], ebx
748
 
749
; and return it to caller
750
        mov     [esp+32], eax
751
        ret
752
 
753
  .block:
754
        test    [eax + SOCKET.options], SO_NONBLOCK
3658 hidnplayr 755
        jnz     .wouldblock
3545 hidnplayr 756
 
757
        call    SOCKET_block
758
        jmp     .loop
759
 
3658 hidnplayr 760
  .wouldblock:
761
        mov     dword[esp+24], EWOULDBLOCK
762
        mov     dword[esp+32], -1
763
        ret
764
 
765
  .invalid:
766
        mov     dword[esp+24], EINVAL
767
        mov     dword[esp+32], -1
768
        ret
769
 
770
  .notsupp:
771
        mov     dword[esp+24], EOPNOTSUPP
772
        mov     dword[esp+32], -1
773
        ret
774
 
3545 hidnplayr 775
;-----------------------------------------------------------------
776
;
777
; SOCKET_close
778
;
779
;  IN:  socket number in ecx
780
;  OUT: eax is socket num, -1 on error
781
;
782
;-----------------------------------------------------------------
783
align 4
784
SOCKET_close:
785
 
3556 hidnplayr 786
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_close: socknum=%u\n", ecx
3545 hidnplayr 787
 
788
        call    SOCKET_num_to_ptr
3658 hidnplayr 789
        jz      .invalid
3545 hidnplayr 790
 
3658 hidnplayr 791
        mov     dword[esp+32], 0                                ; The socket exists, so we will succeed in closing it.
3545 hidnplayr 792
 
793
        or      [eax + SOCKET.options], SO_NONBLOCK             ; Mark the socket as non blocking, we dont want it to block any longer!
794
 
795
        test    [eax + SOCKET.state], SS_BLOCKED                ; Is the socket still in blocked state?
796
        jz      @f
797
        call    SOCKET_notify.unblock                           ; Unblock it.
798
  @@:
799
 
800
        cmp     [eax + SOCKET.Domain], AF_INET4
801
        jne     .free
802
 
803
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
804
        je      .tcp
805
 
806
  .free:
807
        call    SOCKET_free
808
        ret
809
 
810
  .tcp:
811
        cmp     [eax + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED    ; state must be LISTEN, SYN_SENT or CLOSED
812
        jb      .free
813
 
814
        call    TCP_usrclosed
815
        call    TCP_output      ;;;; Fixme: is this nescessary??
3646 hidnplayr 816
        call    SOCKET_free
3545 hidnplayr 817
 
818
        ret
819
 
820
 
3658 hidnplayr 821
  .invalid:
822
        mov     dword[esp+24], EINVAL
823
        mov     dword[esp+32], -1
824
        ret
825
 
826
 
3545 hidnplayr 827
;-----------------------------------------------------------------
828
;
829
; SOCKET_receive
830
;
831
;  IN:  socket number in ecx
832
;       addr to buffer in edx
833
;       length of buffer in esi
834
;       flags in edi
835
;  OUT: eax is number of bytes copied, -1 on error
836
;
837
;-----------------------------------------------------------------
838
align 4
839
SOCKET_receive:
840
 
3556 hidnplayr 841
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_receive: socknum=%u bufaddr=%x buflength=%u flags=%x\n", ecx, edx, esi, edi
3545 hidnplayr 842
 
843
        call    SOCKET_num_to_ptr
3658 hidnplayr 844
        jz      .invalid
3545 hidnplayr 845
 
3565 hidnplayr 846
        call    [eax + SOCKET.rcv_proc]
3545 hidnplayr 847
 
3658 hidnplayr 848
        mov     [esp+24], ebx
3565 hidnplayr 849
        mov     [esp+32], eax
850
        ret
3545 hidnplayr 851
 
3565 hidnplayr 852
 
3658 hidnplayr 853
  .invalid:
854
        mov     dword[esp+24], EINVAL
855
        mov     dword[esp+32], -1
856
        ret
857
 
3545 hidnplayr 858
align 4
859
SOCKET_receive_dgram:
3556 hidnplayr 860
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_receive: DGRAM\n"
3545 hidnplayr 861
 
862
        mov     ebx, esi
863
        mov     edi, edx                                        ; addr to buffer
864
 
865
  .loop:
866
        get_from_queue (eax + SOCKET_QUEUE_LOCATION), SOCKET_QUEUE_SIZE, sizeof.socket_queue_entry, .block      ; destroys esi and ecx
867
 
868
        mov     ecx, [esi + socket_queue_entry.data_size]
3556 hidnplayr 869
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_receive: %u bytes data\n", ecx
3545 hidnplayr 870
 
871
        cmp     ecx, ebx
872
        ja      .too_small
873
 
3565 hidnplayr 874
        push    ecx
3545 hidnplayr 875
        push    [esi + socket_queue_entry.buf_ptr]              ; save the buffer addr so we can clear it later
876
        mov     esi, [esi + socket_queue_entry.data_ptr]
3556 hidnplayr 877
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_receive: Source buffer=%x real addr=%x\n", [esp], esi
3545 hidnplayr 878
 
879
; copy the data
880
        shr     ecx, 1
881
        jnc     .nb
882
        movsb
883
  .nb:
884
        shr     ecx, 1
885
        jnc     .nw
886
        movsw
887
  .nw:
888
        test    ecx, ecx
889
        jz      .nd
890
        rep     movsd
891
  .nd:
892
 
893
        call    kernel_free                                     ; remove the packet
3565 hidnplayr 894
        pop     eax
3545 hidnplayr 895
        ret
896
 
897
  .too_small:
3565 hidnplayr 898
        mov     eax, -1
3658 hidnplayr 899
        mov     ebx, EMSGSIZE
3565 hidnplayr 900
        ret
3545 hidnplayr 901
 
902
  .block:
903
        test    [eax + SOCKET.options], SO_NONBLOCK
3658 hidnplayr 904
        jnz     .wouldblock
3545 hidnplayr 905
 
906
        call    SOCKET_block
907
        jmp     .loop
908
 
3658 hidnplayr 909
  .wouldblock:
910
        mov     eax, -1
911
        mov     ebx, EWOULDBLOCK
912
        ret
3545 hidnplayr 913
 
3658 hidnplayr 914
 
3545 hidnplayr 915
align 4
916
SOCKET_receive_local:
917
 
918
        ; does this socket have a PID yet?
919
        cmp     [eax + SOCKET.PID], 0
920
        jne     @f
921
 
922
        ; Change PID to that of current process
923
        mov     ebx, [TASK_BASE]
924
        mov     ebx, [ebx + TASKDATA.pid]
925
        mov     [eax + SOCKET.PID], ebx
926
        mov     [eax + SOCKET.TID], ebx         ; currently TID = PID in kolibrios :(
927
      @@:
928
 
929
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_stream
930
 
931
align 4
932
SOCKET_receive_stream:
933
 
3556 hidnplayr 934
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_receive: STREAM\n"
3545 hidnplayr 935
 
936
        mov     ebx, edi
937
        mov     ecx, esi
938
        mov     edi, edx
939
        xor     edx, edx
940
 
941
        test    ebx, MSG_DONTWAIT
942
        jnz     .dontwait
943
  .loop:
944
        cmp     [eax + STREAM_SOCKET.rcv + RING_BUFFER.size], 0
945
        je      .block
946
  .dontwait:
947
        test    ebx, MSG_PEEK
948
        jnz     .peek
949
 
950
        add     eax, STREAM_SOCKET.rcv
951
        call    SOCKET_ring_read
952
        call    SOCKET_ring_free
953
 
3565 hidnplayr 954
        mov     eax, ecx                ; return number of bytes copied
3545 hidnplayr 955
        ret
956
 
957
  .peek:
3565 hidnplayr 958
        mov     eax, [eax + STREAM_SOCKET.rcv + RING_BUFFER.size]
3545 hidnplayr 959
        ret
960
 
961
  .block:
962
        test    [eax + SOCKET.options], SO_NONBLOCK
3658 hidnplayr 963
        jnz     .wouldblock
3545 hidnplayr 964
 
965
        call    SOCKET_block
966
        jmp     .loop
967
 
968
  .return0:
3565 hidnplayr 969
        test    [eax + SOCKET.options], SS_CANTRCVMORE
970
        jz      .ok
971
 
972
        xor     eax, eax
973
        dec     eax
3545 hidnplayr 974
        ret
975
 
3565 hidnplayr 976
  .ok:
977
        xor     eax, eax
978
        ret
3545 hidnplayr 979
 
3658 hidnplayr 980
  .wouldblock:
981
        mov     eax, -1
982
        mov     ebx, EWOULDBLOCK
983
        ret
3565 hidnplayr 984
 
3658 hidnplayr 985
 
986
 
3545 hidnplayr 987
;-----------------------------------------------------------------
988
;
989
; SOCKET_send
990
;
991
;
992
;  IN:  socket number in ecx
993
;       pointer to data in edx
994
;       datalength in esi
995
;       flags in edi
996
;  OUT: -1 on error
997
;
998
;-----------------------------------------------------------------
999
align 4
1000
SOCKET_send:
1001
 
3556 hidnplayr 1002
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_send: socknum=%u data ptr=%x length=%u flags=%x\n", ecx, edx, esi, edi
3545 hidnplayr 1003
 
1004
        call    SOCKET_num_to_ptr
3658 hidnplayr 1005
        jz      .invalid
3545 hidnplayr 1006
 
1007
        mov     ecx, esi
1008
        mov     esi, edx
1009
 
1010
        jmp     [eax + SOCKET.snd_proc]
1011
 
3658 hidnplayr 1012
  .invalid:
1013
        mov     dword[esp+24], EINVAL
1014
        mov     dword[esp+32], -1
1015
        ret
3545 hidnplayr 1016
 
3658 hidnplayr 1017
 
3545 hidnplayr 1018
align 4
1019
SOCKET_send_udp:
1020
 
3556 hidnplayr 1021
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_send: UDP\n"
3545 hidnplayr 1022
 
1023
        mov     [esp+32], ecx
1024
        call    UDP_output
1025
        cmp     eax, -1
3658 hidnplayr 1026
        je      .error
3545 hidnplayr 1027
        ret
1028
 
3658 hidnplayr 1029
  .error:
1030
        mov     dword[esp+32], -1
1031
        mov     dword[esp+24], EMSGSIZE ; FIXME: UDP_output should return error codes!
1032
        ret
3545 hidnplayr 1033
 
3658 hidnplayr 1034
 
3545 hidnplayr 1035
align 4
1036
SOCKET_send_tcp:
1037
 
3556 hidnplayr 1038
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_send: TCP\n"
3545 hidnplayr 1039
 
1040
        push    eax
1041
        add     eax, STREAM_SOCKET.snd
1042
        call    SOCKET_ring_write
1043
        pop     eax
1044
 
1045
        mov     [esp+32], ecx
3658 hidnplayr 1046
        mov     [eax + SOCKET.errorcode], 0
1047
        push    eax
1048
        call    TCP_output              ; FIXME: this doesnt look pretty, does it?
1049
        pop     eax
1050
        mov     eax, [eax + SOCKET.errorcode]
1051
        mov     [esp+24], eax
3545 hidnplayr 1052
        ret
1053
 
1054
 
1055
align 4
1056
SOCKET_send_ip:
1057
 
3556 hidnplayr 1058
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_send: IPv4\n"
3545 hidnplayr 1059
 
1060
        mov     [esp+32], ecx
3658 hidnplayr 1061
        call    IPv4_output_raw         ; FIXME: IPv4_output_raw should return error codes!
3545 hidnplayr 1062
        cmp     eax, -1
3658 hidnplayr 1063
        je      .error
3545 hidnplayr 1064
        ret
1065
 
3658 hidnplayr 1066
  .error:
1067
        mov     dword[esp+32], -1
1068
        mov     dword[esp+24], EMSGSIZE
1069
        ret
3545 hidnplayr 1070
 
3658 hidnplayr 1071
 
3545 hidnplayr 1072
align 4
1073
SOCKET_send_icmp:
1074
 
3556 hidnplayr 1075
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_send: ICMP\n"
3545 hidnplayr 1076
 
1077
        mov     [esp+32], ecx
3658 hidnplayr 1078
        call    ICMP_output_raw         ; FIXME: errorcodes
3545 hidnplayr 1079
        cmp     eax, -1
3658 hidnplayr 1080
        je      .error
3545 hidnplayr 1081
        ret
1082
 
3658 hidnplayr 1083
  .error:
1084
        mov     dword[esp+32], -1
1085
        mov     dword[esp+24], EMSGSIZE
1086
        ret
3545 hidnplayr 1087
 
3658 hidnplayr 1088
 
3545 hidnplayr 1089
align 4
1090
SOCKET_send_pppoe:
1091
 
3556 hidnplayr 1092
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_send: PPPoE\n"
3545 hidnplayr 1093
 
1094
        mov     [esp+32], ecx
1095
        mov     ebx, [eax + SOCKET.device]
1096
 
3658 hidnplayr 1097
        call    PPPoE_discovery_output  ; FIXME: errorcodes
3545 hidnplayr 1098
        cmp     eax, -1
3658 hidnplayr 1099
        je      .error
3545 hidnplayr 1100
        ret
1101
 
3658 hidnplayr 1102
  .error:
1103
        mov     dword[esp+32], -1
1104
        mov     dword[esp+24], EMSGSIZE
1105
        ret
3545 hidnplayr 1106
 
1107
 
3658 hidnplayr 1108
 
3545 hidnplayr 1109
align 4
1110
SOCKET_send_local:
1111
 
1112
        ; does this socket have a PID yet?
1113
        cmp     [eax + SOCKET.PID], 0
1114
        jne     @f
1115
 
1116
        ; Change PID to that of current process
1117
        mov     ebx, [TASK_BASE]
1118
        mov     ebx, [ebx + TASKDATA.pid]
1119
        mov     [eax + SOCKET.PID], ebx
1120
        mov     [eax + SOCKET.TID], ebx         ; currently TID = PID in kolibrios :(
1121
      @@:
1122
        mov     [eax + SOCKET.snd_proc], SOCKET_send_local_
1123
 
1124
align 4
1125
SOCKET_send_local_:
1126
 
3556 hidnplayr 1127
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_send: LOCAL\n"
3545 hidnplayr 1128
 
1129
        ; get the other side's socket and check if it still exists
1130
        mov     eax, [eax + SOCKET.device]
1131
        call    SOCKET_check
3658 hidnplayr 1132
        jz      .invalid
3545 hidnplayr 1133
 
1134
        ; allright, shove in the data!
1135
        push    eax
1136
        add     eax, STREAM_SOCKET.rcv
1137
        call    SOCKET_ring_write
1138
        pop     eax
1139
 
1140
        ; return the number of written bytes (or errorcode) to application
1141
        mov     [esp+32], ecx
1142
 
1143
        ; and notify the other end
1144
        call    SOCKET_notify
1145
 
1146
        ret
1147
 
3658 hidnplayr 1148
  .invalid:
1149
        mov     dword[esp+32], -1
1150
        mov     dword[esp+24], EINVAL
1151
        ret
3545 hidnplayr 1152
 
3658 hidnplayr 1153
 
3545 hidnplayr 1154
;-----------------------------------------------------------------
1155
;
1156
; SOCKET_get_options
1157
;
1158
;  IN:  ecx = socket number
1159
;       edx = pointer to the options:
1160
;               dd      level, optname, optval, optlen
1161
;  OUT: -1 on error
1162
;
1163
; At moment, uses only pseudo-optname -2 for get last_ack_number for TCP.
1164
; TODO: find best way to notify that send()'ed data were acknowledged
1165
; Also pseudo-optname -3 is valid and returns socket state, one of TCPS_*.
1166
;
1167
;-----------------------------------------------------------------
1168
align 4
1169
SOCKET_get_opt:
1170
 
3556 hidnplayr 1171
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_get_opt\n"
3545 hidnplayr 1172
 
1173
        call    SOCKET_num_to_ptr
3658 hidnplayr 1174
        jz      .invalid
3545 hidnplayr 1175
 
1176
        cmp     dword [edx], IP_PROTO_TCP
3658 hidnplayr 1177
        jne     .invalid
3545 hidnplayr 1178
        cmp     dword [edx+4], -2
1179
        je      @f
1180
        cmp     dword [edx+4], -3
3658 hidnplayr 1181
        jne     .invalid
3545 hidnplayr 1182
@@:
1183
;        mov     eax, [edx+12]
1184
;        test    eax, eax
1185
;        jz      .fail
1186
;        cmp     dword [eax], 4
1187
;        mov     dword [eax], 4
1188
;        jb      .fail
1189
;        stdcall net_socket_num_to_addr, ecx
1190
;        test    eax, eax
1191
;        jz      .fail
1192
;        ; todo: check that eax is really TCP socket
1193
;        mov     ecx, [eax + TCP_SOCKET.last_ack_number]
1194
;        cmp     dword [edx+4], -2
1195
;        jz      @f
1196
;        mov     ecx, [eax + TCP_SOCKET.state]
1197
@@:
1198
        mov     eax, [edx+8]
1199
        test    eax, eax
1200
        jz      @f
1201
        mov     [eax], ecx
1202
@@:
1203
        mov     dword [esp+32], 0
1204
        ret
1205
 
3658 hidnplayr 1206
  .invalid:
1207
        mov     dword[esp+32], -1
1208
        mov     dword[esp+24], EINVAL
1209
        ret
3545 hidnplayr 1210
 
1211
 
3658 hidnplayr 1212
 
3545 hidnplayr 1213
;-----------------------------------------------------------------
1214
;
1215
; SOCKET_set_options
1216
;
1217
;  IN:  ecx = socket number
1218
;       edx = pointer to the options:
1219
;               dd      level, optname, optlen, optval
1220
;  OUT: -1 on error
1221
;
1222
;-----------------------------------------------------------------
1223
align 4
1224
SOCKET_set_opt:
1225
 
3556 hidnplayr 1226
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_set_opt\n"
3545 hidnplayr 1227
 
1228
        call    SOCKET_num_to_ptr
3658 hidnplayr 1229
        jz      .invalid
3545 hidnplayr 1230
 
1231
        cmp     dword [edx], SOL_SOCKET
3658 hidnplayr 1232
        jne     .invalid
3545 hidnplayr 1233
 
1234
        cmp     dword [edx+4], SO_BINDTODEVICE
1235
        je      .bind
1236
 
1237
        cmp     dword [edx+4], SO_BLOCK
1238
        je      .block
1239
 
3658 hidnplayr 1240
  .invalid:
1241
        mov     dword[esp+32], -1
1242
        mov     dword[esp+24], EINVAL
1243
        ret
3545 hidnplayr 1244
 
1245
  .bind:
3658 hidnplayr 1246
        cmp     dword[edx+8], 0
3545 hidnplayr 1247
        je      .unbind
1248
 
3658 hidnplayr 1249
        movzx   edx, byte[edx + 9]
3600 hidnplayr 1250
        cmp     edx, NET_DEVICES_MAX
3658 hidnplayr 1251
        ja      .invalid
3545 hidnplayr 1252
 
1253
        mov     edx, [NET_DRV_LIST + 4*edx]
1254
        test    edx, edx
3658 hidnplayr 1255
        jz      .already
3545 hidnplayr 1256
        mov     [eax + SOCKET.device], edx
1257
 
3556 hidnplayr 1258
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_set_opt: Bound socket %x to device %x\n",eax, edx
3545 hidnplayr 1259
 
3658 hidnplayr 1260
        mov     dword[esp+32], 0        ; success!
3545 hidnplayr 1261
        ret
1262
 
1263
  .unbind:
1264
        mov     [eax + SOCKET.device], 0
1265
 
3658 hidnplayr 1266
        mov     dword[esp+32], 0        ; success!
3545 hidnplayr 1267
        ret
1268
 
1269
  .block:
3658 hidnplayr 1270
        cmp     dword[edx+8], 0
3545 hidnplayr 1271
        je      .unblock
1272
 
1273
        and     [eax + SOCKET.options], not SO_NONBLOCK
1274
 
3658 hidnplayr 1275
        mov     dword[esp+32], 0        ; success!
3545 hidnplayr 1276
        ret
1277
 
1278
  .unblock:
1279
        or      [eax + SOCKET.options], SO_NONBLOCK
1280
 
3658 hidnplayr 1281
        mov     dword[esp+32], 0        ; success!
3545 hidnplayr 1282
        ret
1283
 
3658 hidnplayr 1284
  .already:
1285
        mov     dword[esp+24], EALREADY
1286
        mov     dword[esp+32], -1
1287
        ret
3545 hidnplayr 1288
 
1289
 
3658 hidnplayr 1290
 
1291
 
3545 hidnplayr 1292
;-----------------------------------------------------------------
1293
;
1294
; SOCKET_pair
1295
;
1296
; Allocates a pair of linked LOCAL domain sockets
1297
;
1298
; IN: /
1299
; OUT: eax is socket1 num, -1 on error
1300
;      ebx is socket2 num
1301
;
1302
;-----------------------------------------------------------------
1303
align 4
1304
SOCKET_pair:
1305
 
3556 hidnplayr 1306
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_pair\n"
3545 hidnplayr 1307
 
1308
        call    SOCKET_alloc
3658 hidnplayr 1309
        jz      .nomem1
3545 hidnplayr 1310
        mov     [esp+32], edi   ; application's eax
1311
 
1312
        mov     [eax + SOCKET.Domain], AF_LOCAL
1313
        mov     [eax + SOCKET.Type], SOCK_STREAM
1314
        mov     [eax + SOCKET.Protocol], 0              ;;; CHECKME
1315
        mov     [eax + SOCKET.snd_proc], SOCKET_send_local
1316
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_local
1317
        mov     [eax + SOCKET.PID], 0
1318
        mov     ebx, eax
1319
 
1320
        call    SOCKET_alloc
3658 hidnplayr 1321
        jz      .nomem2
3545 hidnplayr 1322
        mov     [esp+24], edi   ; application's ebx
1323
 
1324
        mov     [eax + SOCKET.Domain], AF_LOCAL
1325
        mov     [eax + SOCKET.Type], SOCK_STREAM
1326
        mov     [eax + SOCKET.Protocol], 0              ;;; CHECKME
1327
        mov     [eax + SOCKET.snd_proc], SOCKET_send_local
1328
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_local
1329
        mov     [eax + SOCKET.PID], 0
1330
 
1331
        ; Link the two sockets to eachother
1332
        mov     [eax + SOCKET.device], ebx
1333
        mov     [ebx + SOCKET.device], eax
1334
 
1335
        lea     eax, [eax + STREAM_SOCKET.rcv]
1336
        call    SOCKET_ring_create
1337
 
1338
        lea     eax, [ebx + STREAM_SOCKET.rcv]
1339
        call    SOCKET_ring_create
1340
        pop     eax
1341
 
1342
        ret
1343
 
3658 hidnplayr 1344
  .nomem2:
3545 hidnplayr 1345
        mov     eax, ebx
1346
        call    SOCKET_free
3658 hidnplayr 1347
  .nomem1:
1348
        mov     dword[esp+32], -1
1349
        mov     dword[esp+28], ENOMEM
1350
        ret
3545 hidnplayr 1351
 
1352
 
1353
 
1354
;-----------------------------------------------------------------
1355
;
1356
; SOCKET_debug
1357
;
1358
;  Copies socket variables to application buffer
1359
;
1360
;  IN:  ecx = socket number
1361
;       edx = pointer to buffer
1362
;
1363
;  OUT: -1 on error
1364
;-----------------------------------------------------------------
1365
align 4
1366
SOCKET_debug:
1367
 
3556 hidnplayr 1368
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_debug\n"
3545 hidnplayr 1369
 
1370
        mov     edi, edx
1371
 
1372
        test    ecx, ecx
1373
        jz      .returnall
1374
 
1375
        call    SOCKET_num_to_ptr
3658 hidnplayr 1376
        jz      .invalid
3545 hidnplayr 1377
 
1378
        mov     esi, eax
1379
        mov     ecx, SOCKETBUFFSIZE/4
1380
        rep     movsd
1381
 
3658 hidnplayr 1382
        mov     dword[esp+32], 0
3545 hidnplayr 1383
        ret
1384
 
1385
  .returnall:
1386
        mov     ebx, net_sockets
1387
  .next_socket:
1388
        mov     ebx, [ebx + SOCKET.NextPtr]
1389
        test    ebx, ebx
1390
        jz      .done
1391
        mov     eax, [ebx + SOCKET.Number]
1392
        stosd
1393
        jmp     .next_socket
1394
  .done:
1395
        xor     eax, eax
1396
        stosd
3658 hidnplayr 1397
        mov     dword[esp+32], eax
1398
        ret
3545 hidnplayr 1399
 
3658 hidnplayr 1400
  .invalid:
1401
        mov     dword[esp+32], -1
1402
        mov     dword[esp+28], EINVAL
3545 hidnplayr 1403
        ret
1404
 
1405
 
1406
;-----------------------------------------------------------------
1407
;
1408
; SOCKET_find_port
1409
;
1410
; Fills in the local port number for TCP and UDP sockets
1411
; This procedure always works because the number of sockets is
1412
; limited to a smaller number then the number of possible ports
1413
;
1414
;  IN:  eax = socket pointer
1415
;  OUT: /
1416
;
1417
;-----------------------------------------------------------------
1418
align 4
1419
SOCKET_find_port:
1420
 
3556 hidnplayr 1421
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_find_port\n"
3545 hidnplayr 1422
 
1423
        push    ebx esi ecx
1424
 
1425
        cmp     [eax + SOCKET.Protocol], IP_PROTO_UDP
1426
        je      .udp
1427
 
1428
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
1429
        je      .tcp
1430
 
1431
        pop     ecx esi ebx
1432
        ret
1433
 
1434
  .udp:
1435
        mov     bx, [last_UDP_port]
1436
        call    .findit
1437
        mov     [last_UDP_port], bx
1438
 
1439
        pop     ecx esi ebx
1440
        ret
1441
 
1442
  .tcp:
1443
        mov     bx, [last_TCP_port]
1444
        call    .findit
1445
        mov     [last_TCP_port], bx
1446
 
1447
        pop     ecx esi ebx
1448
        ret
1449
 
1450
 
1451
  .restart:
1452
        mov     bx, MIN_EPHEMERAL_PORT_N
1453
  .findit:
1454
        cmp     bx, MAX_EPHEMERAL_PORT_N
1455
        je      .restart
1456
 
1457
        add     bh, 1
1458
        adc     bl, 0
1459
 
1460
        call    SOCKET_check_port
1461
        jz      .findit
1462
        ret
1463
 
1464
 
1465
 
1466
;-----------------------------------------------------------------
1467
;
1468
; SOCKET_check_port (to be used with AF_INET only!)
1469
;
1470
; Checks if a local port number is unused
1471
; If the proposed port number is unused, it is filled in in the socket structure
1472
;
1473
;  IN:  eax = socket ptr (to find out if its a TCP/UDP socket)
1474
;        bx = proposed socket number (network byte order)
1475
;
1476
;  OUT:  ZF = set on error
1477
;
1478
;-----------------------------------------------------------------
1479
align 4
1480
SOCKET_check_port:
1481
 
3556 hidnplayr 1482
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_check_port: "
3545 hidnplayr 1483
 
3647 hidnplayr 1484
        pusha
1485
        mov     ecx, socket_mutex
1486
        call    mutex_lock
1487
        popa
1488
 
3545 hidnplayr 1489
        mov     ecx, [eax + SOCKET.Protocol]
1490
        mov     edx, [eax + IP_SOCKET.LocalIP]
1491
        mov     esi, net_sockets
1492
 
1493
  .next_socket:
1494
        mov     esi, [esi + SOCKET.NextPtr]
1495
        or      esi, esi
1496
        jz      .port_ok
1497
 
1498
        cmp     [esi + SOCKET.Protocol], ecx
1499
        jne     .next_socket
1500
 
1501
        cmp     [esi + IP_SOCKET.LocalIP], edx
1502
        jne     .next_socket
1503
 
1504
        cmp     [esi + UDP_SOCKET.LocalPort], bx
1505
        jne     .next_socket
1506
 
3647 hidnplayr 1507
        pusha
1508
        mov     ecx, socket_mutex
1509
        call    mutex_unlock
1510
        popa
1511
 
3556 hidnplayr 1512
        DEBUGF  DEBUG_NETWORK_VERBOSE, "local port %x already in use\n", bx  ; FIXME: find a way to print big endian values with debugf
3545 hidnplayr 1513
        ret
1514
 
1515
  .port_ok:
3647 hidnplayr 1516
        pusha
1517
        mov     ecx, socket_mutex
1518
        call    mutex_unlock
1519
        popa
1520
 
3556 hidnplayr 1521
        DEBUGF  DEBUG_NETWORK_VERBOSE, "local port %x is free\n", bx         ; FIXME: find a way to print big endian values with debugf
3545 hidnplayr 1522
        mov     [eax + UDP_SOCKET.LocalPort], bx
1523
        or      bx, bx                                  ; clear the zero-flag
1524
        ret
1525
 
1526
 
1527
 
1528
;-----------------------------------------------------------------
1529
;
1530
; SOCKET_input
1531
;
1532
; Updates a (stateless) socket with received data
1533
;
1534
; Note: the mutex should already be set !
1535
;
1536
;  IN:  eax = socket ptr
1537
;       ecx = data size
1538
;       esi = ptr to data
1539
;       [esp] = ptr to buf
1540
;       [esp + 4] = buf size
1541
;
1542
;  OUT: /
1543
;
1544
;-----------------------------------------------------------------
1545
align 4
1546
SOCKET_input:
1547
 
3556 hidnplayr 1548
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_input: socket=%x, data=%x size=%u\n", eax, esi, ecx
3545 hidnplayr 1549
 
1550
        mov     [esp+4], ecx
1551
        push    esi
1552
        mov     esi, esp
1553
 
1554
        add_to_queue (eax + SOCKET_QUEUE_LOCATION), SOCKET_QUEUE_SIZE, sizeof.socket_queue_entry, SOCKET_input.full
1555
 
3556 hidnplayr 1556
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_input: success\n"
3545 hidnplayr 1557
        add     esp, sizeof.socket_queue_entry
1558
 
1559
        pusha
1560
        lea     ecx, [eax + SOCKET.mutex]
1561
        call    mutex_unlock
1562
        popa
1563
 
1564
        jmp     SOCKET_notify
1565
 
1566
  .full:
3556 hidnplayr 1567
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_input: socket %x is full!\n", eax
3545 hidnplayr 1568
 
1569
        pusha
1570
        lea     ecx, [eax + SOCKET.mutex]
1571
        call    mutex_unlock
1572
        popa
1573
 
1574
        call    kernel_free
1575
        add     esp, 8
1576
 
1577
        ret
1578
 
1579
 
1580
;--------------------------
1581
;
1582
; eax = ptr to ring struct (just a buffer of the right size)
1583
;
1584
align 4
1585
SOCKET_ring_create:
1586
 
1587
        push    esi
1588
        mov     esi, eax
1589
 
1590
        push    edx
1591
        stdcall create_ring_buffer, SOCKET_MAXDATA, PG_SW
1592
        pop     edx
1593
 
3556 hidnplayr 1594
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_created: %x\n", eax
3545 hidnplayr 1595
 
1596
        pusha
1597
        lea     ecx, [esi + RING_BUFFER.mutex]
1598
        call    mutex_init
1599
        popa
1600
 
1601
        mov     [esi + RING_BUFFER.start_ptr], eax
1602
        mov     [esi + RING_BUFFER.write_ptr], eax
1603
        mov     [esi + RING_BUFFER.read_ptr], eax
1604
        mov     [esi + RING_BUFFER.size], 0
1605
        add     eax, SOCKET_MAXDATA
1606
        mov     [esi + RING_BUFFER.end_ptr], eax
1607
        mov     eax, esi
1608
        pop     esi
1609
 
1610
        ret
1611
 
1612
;-----------------------------------------------------------------
1613
;
1614
; SOCKET_ring_write
1615
;
1616
; Adds data to a stream socket, and updates write pointer and size
1617
;
1618
;  IN:  eax = ptr to ring struct
1619
;       ecx = data size
1620
;       esi = ptr to data
1621
;
1622
;  OUT: ecx = number of bytes stored
1623
;
1624
;-----------------------------------------------------------------
1625
align 4
1626
SOCKET_ring_write:
1627
 
3556 hidnplayr 1628
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_write: ringbuff=%x ptr=%x size=%u\n", eax, esi, ecx
3545 hidnplayr 1629
 
1630
; lock mutex
1631
        pusha
1632
        lea     ecx, [eax + RING_BUFFER.mutex]
1633
        call    mutex_lock                                      ; TODO: check what registers this function actually destroys
1634
        popa
1635
 
1636
; calculate available size
1637
        mov     edi, SOCKET_MAXDATA
1638
        sub     edi, [eax + RING_BUFFER.size]                   ; available buffer size in edi
1639
        cmp     ecx, edi
1640
        jbe     .copy
1641
        mov     ecx, edi
1642
  .copy:
1643
        mov     edi, [eax + RING_BUFFER.write_ptr]
3556 hidnplayr 1644
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_write: %u bytes from %x to %x\n", ecx, esi, edi
3545 hidnplayr 1645
 
1646
; update write ptr
1647
        push    edi
1648
        add     edi, ecx
1649
        cmp     edi, [eax + RING_BUFFER.end_ptr]
1650
        jb      @f
1651
        sub     edi, SOCKET_MAXDATA                             ; WRAP
1652
  @@:
1653
        mov     [eax + RING_BUFFER.write_ptr], edi
1654
        pop     edi
1655
 
1656
; update size
1657
        add     [eax + RING_BUFFER.size], ecx
1658
 
1659
; copy the data
1660
        push    ecx
1661
        shr     ecx, 1
1662
        jnc     .nb
1663
        movsb
1664
  .nb:
1665
        shr     ecx, 1
1666
        jnc     .nw
1667
        movsw
1668
  .nw:
1669
        test    ecx, ecx
1670
        jz      .nd
1671
        rep     movsd
1672
  .nd:
1673
        pop     ecx
1674
 
1675
; unlock mutex
1676
        push    eax ecx
1677
        lea     ecx, [eax + RING_BUFFER.mutex]
1678
        call    mutex_unlock                                    ; TODO: check what registers this function actually destroys
1679
        pop     ecx eax
1680
 
1681
        ret
1682
 
1683
;-----------------------------------------------------------------
1684
;
1685
; SOCKET_ring_read
1686
;
1687
;  IN:  eax = ring struct ptr
1688
;       ecx = bytes to read
1689
;       edx = offset
1690
;       edi = ptr to buffer start
1691
;
1692
;  OUT: eax = unchanged
1693
;       ecx = number of bytes read (0 on error)
1694
;       edx = destroyed
1695
;       esi = destroyed
1696
;       edi = ptr to buffer end
1697
;
1698
;-----------------------------------------------------------------
1699
align 4
1700
SOCKET_ring_read:
1701
 
3556 hidnplayr 1702
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_read: ringbuff=%x ptr=%x size=%u offset=%x\n", eax, edi, ecx, edx
3545 hidnplayr 1703
 
1704
        pusha
1705
        lea     ecx, [eax + RING_BUFFER.mutex]
1706
        call    mutex_lock                                      ; TODO: check what registers this function actually destroys
1707
        popa
1708
 
1709
        mov     esi, [eax + RING_BUFFER.read_ptr]
1710
        add     esi, edx                                        ; esi = start_ptr + offset
1711
 
1712
        neg     edx
1713
        add     edx, [eax + RING_BUFFER.size]                   ; edx = snd.size - offset
1714
        jle     .no_data_at_all
1715
 
1716
        pusha
1717
        lea     ecx, [eax + RING_BUFFER.mutex]
1718
        call    mutex_unlock                                    ; TODO: check what registers this function actually destroys
1719
        popa
1720
 
1721
        cmp     ecx, edx
1722
        ja      .less_data
1723
 
1724
  .copy:
3556 hidnplayr 1725
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_read: %u bytes from %x to %x\n", ecx, esi, edi
3545 hidnplayr 1726
        push    ecx
1727
        shr     ecx, 1
1728
        jnc     .nb
1729
        movsb
1730
  .nb:
1731
        shr     ecx, 1
1732
        jnc     .nw
1733
        movsw
1734
  .nw:
1735
        test    ecx, ecx
1736
        jz      .nd
1737
        rep     movsd
1738
  .nd:
1739
        pop     ecx
1740
        ret
1741
 
1742
  .no_data_at_all:
1743
        pusha
1744
        lea     ecx, [eax + RING_BUFFER.mutex]
1745
        call    mutex_unlock                                    ; TODO: check what registers this function actually destroys
1746
        popa
1747
 
3556 hidnplayr 1748
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_read: no data at all!\n"
3545 hidnplayr 1749
        xor     ecx, ecx
1750
        ret
1751
 
1752
  .less_data:
1753
        mov     ecx, edx
1754
        jmp     .copy
1755
 
1756
 
1757
;-----------------------------------------------------------------
1758
;
1759
; SOCKET_ring_free
1760
;
1761
; Free's some bytes from the ringbuffer
1762
;
1763
;  IN:  eax = ptr to ring struct
1764
;       ecx = data size
1765
;
1766
;  OUT: ecx = number of bytes free-ed
1767
;
1768
;-----------------------------------------------------------------
1769
align 4
1770
SOCKET_ring_free:
1771
 
3556 hidnplayr 1772
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_free: %u bytes from ring %x\n", ecx, eax
3545 hidnplayr 1773
 
1774
        push    eax ecx
1775
        lea     ecx, [eax + RING_BUFFER.mutex]
1776
        call    mutex_lock                                      ; TODO: check what registers this function actually destroys
1777
        pop     ecx eax
1778
 
1779
        sub     [eax + RING_BUFFER.size], ecx
1780
        jb      .error
1781
        add     [eax + RING_BUFFER.read_ptr], ecx
1782
 
1783
        mov     edx, [eax + RING_BUFFER.end_ptr]
1784
        cmp     [eax + RING_BUFFER.read_ptr], edx
1785
        jb      @f
1786
        sub     [eax + RING_BUFFER.read_ptr], SOCKET_MAXDATA
1787
       @@:
1788
 
1789
        push    eax ecx
1790
        lea     ecx, [eax + RING_BUFFER.mutex]                  ; TODO: check what registers this function actually destroys
1791
        call    mutex_unlock
1792
        pop     ecx eax
1793
 
1794
        ret
1795
 
1796
  .error:       ; we could free all available bytes, but that would be stupid, i guess..
3556 hidnplayr 1797
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_free: buffer=%x error!\n", eax
3545 hidnplayr 1798
        add     [eax + RING_BUFFER.size], ecx
1799
 
1800
        push    eax
1801
        lea     ecx, [eax + RING_BUFFER.mutex]
1802
        call    mutex_unlock                                    ; TODO: check what registers this function actually destroys
1803
        pop     eax
1804
 
1805
        xor     ecx, ecx
1806
        ret
1807
 
1808
 
1809
;-----------------------------------------------------------------
1810
;
1811
; SOCKET_block
1812
;
1813
; Suspends the thread attached to a socket
1814
;
1815
;  IN:  eax = socket ptr
1816
;  OUT: /
1817
;
1818
;-----------------------------------------------------------------
1819
align 4
1820
SOCKET_block:
1821
 
3556 hidnplayr 1822
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_block: %x\n", eax
3545 hidnplayr 1823
 
1824
        pushf
1825
        cli
1826
 
1827
        ; Set the 'socket is blocked' flag
1828
        or      [eax + SOCKET.state], SS_BLOCKED
1829
 
1830
        ; Suspend the thread
1831
        push    edx
1832
        mov     edx, [TASK_BASE]
1833
        mov     [edx + TASKDATA.state], 1               ; Suspended
1834
 
1835
        ; Remember the thread ID so we can wake it up again
1836
        mov     edx, [edx + TASKDATA.pid]
3556 hidnplayr 1837
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_block: suspending thread: %u\n", edx
3545 hidnplayr 1838
        mov     [eax + SOCKET.TID], edx
1839
        pop     edx
1840
 
1841
        call    change_task
1842
        popf
1843
 
3556 hidnplayr 1844
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_block: continueing\n"
3545 hidnplayr 1845
 
1846
        ret
1847
 
1848
 
1849
;-----------------------------------------------------------------
1850
;
1851
; SOCKET_notify
1852
;
1853
; notify's the owner of a socket that something happened
1854
;
1855
;  IN:  eax = socket ptr
1856
;  OUT: /
1857
;
1858
;-----------------------------------------------------------------
1859
align 4
1860
SOCKET_notify:
1861
 
3556 hidnplayr 1862
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_notify: %x\n", eax
3545 hidnplayr 1863
 
1864
        call    SOCKET_check
1865
        jz      .error
1866
 
1867
        test    [eax + SOCKET.state], SS_BLOCKED
1868
        jnz     .unblock
1869
 
1870
        test    [eax + SOCKET.options], SO_NONBLOCK
1871
        jz      .error
1872
 
1873
        push    eax ecx esi
1874
 
1875
; socket exists and is of non blocking type.
1876
; We'll try to flag an event to the thread
1877
 
1878
        mov     eax, [eax + SOCKET.TID]
1879
        test    eax, eax
1880
        jz      .done
1881
        mov     ecx, 1
1882
        mov     esi, TASK_DATA + TASKDATA.pid
1883
 
1884
  .next_pid:
1885
        cmp     [esi], eax
1886
        je      .found_pid
1887
        inc     ecx
1888
        add     esi, 0x20
1889
        cmp     ecx, [TASK_COUNT]
1890
        jbe     .next_pid
1891
; PID not found, TODO: close socket!
1892
        jmp     .done
1893
 
1894
  .found_pid:
1895
        shl     ecx, 8
1896
        or      [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK
1897
 
3556 hidnplayr 1898
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_notify: Raised a network event!\n"
3545 hidnplayr 1899
 
1900
        jmp     .done
1901
 
1902
  .unblock:
1903
        push    eax ecx esi
1904
        ; Clear the 'socket is blocked' flag
1905
        and     [eax + SOCKET.state], not SS_BLOCKED
1906
 
1907
        ; Find the thread's TASK_DATA
1908
        mov     eax, [eax + SOCKET.TID]
1909
        test    eax, eax
1910
        jz      .error
1911
        xor     ecx, ecx
1912
        inc     ecx
1913
        mov     esi, TASK_DATA
1914
  .next:
1915
        cmp     [esi + TASKDATA.pid], eax
1916
        je      .found
1917
        inc     ecx
1918
        add     esi, 0x20
1919
        cmp     ecx, [TASK_COUNT]
1920
        jbe     .next
1921
        jmp     .error
1922
  .found:
1923
 
1924
        ; Run the thread
1925
        mov     [esi + TASKDATA.state], 0       ; Running
3556 hidnplayr 1926
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_notify: Unblocked socket!\n"
3545 hidnplayr 1927
 
1928
  .done:
1929
        pop     esi ecx eax
1930
 
1931
  .error:
1932
        ret
1933
 
1934
 
1935
;--------------------------------------------------------------------
1936
;
1937
; SOCKET_alloc
1938
;
1939
; Allocate memory for socket data and put new socket into the list
1940
; Newly created socket is initialized with calling PID and number and
1941
; put into beginning of list (which is a fastest way).
1942
;
1943
; IN:  /
1944
; OUT: eax = 0 on error, socket ptr otherwise
1945
;      edi = socket number
1946
;       ZF = cleared on error
1947
;
1948
;--------------------------------------------------------------------
1949
align 4
1950
SOCKET_alloc:
1951
 
1952
        push    ebx
1953
 
1954
        stdcall kernel_alloc, SOCKETBUFFSIZE
3556 hidnplayr 1955
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_alloc: ptr=%x\n", eax
3545 hidnplayr 1956
        or      eax, eax
1957
        jz      .exit
1958
 
1959
; zero-initialize allocated memory
1960
        push    eax
1961
        mov     edi, eax
1962
        mov     ecx, SOCKETBUFFSIZE / 4
1963
        xor     eax, eax
1964
        rep     stosd
1965
        pop     eax
1966
 
1967
; set send-and receive procedures to return -1
3658 hidnplayr 1968
        mov     [eax + SOCKET.snd_proc], .not_yet
1969
        mov     [eax + SOCKET.rcv_proc], .not_yet
3545 hidnplayr 1970
 
3647 hidnplayr 1971
        pusha
1972
        mov     ecx, socket_mutex
1973
        call    mutex_lock
1974
        popa
1975
 
3545 hidnplayr 1976
; find first free socket number and use it
1977
        mov     edi, [last_socket_num]
1978
  .next_socket_number:
1979
        inc     edi
1980
        jz      .next_socket_number     ; avoid socket nr 0
1981
        cmp     edi, -1
1982
        je      .next_socket_number     ; avoid socket nr -1
1983
        mov     ebx, net_sockets
1984
  .next_socket:
1985
        mov     ebx, [ebx + SOCKET.NextPtr]
1986
        test    ebx, ebx
1987
        jz      .last_socket
1988
 
1989
        cmp     [ebx + SOCKET.Number], edi
1990
        jne     .next_socket
1991
        jmp     .next_socket_number
1992
 
1993
  .last_socket:
1994
        mov     [last_socket_num], edi
1995
        mov     [eax + SOCKET.Number], edi
3556 hidnplayr 1996
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_alloc: number=%u\n", edi
3545 hidnplayr 1997
 
1998
; Fill in PID
1999
        mov     ebx, [TASK_BASE]
2000
        mov     ebx, [ebx + TASKDATA.pid]
2001
        mov     [eax + SOCKET.PID], ebx
2002
        mov     [eax + SOCKET.TID], ebx         ; currently TID = PID in kolibrios :(
2003
 
2004
; init mutex
2005
        pusha
2006
        lea     ecx, [eax + SOCKET.mutex]
2007
        call    mutex_init
2008
        popa
2009
 
2010
; add socket to the list by re-arranging some pointers
2011
        mov     ebx, [net_sockets + SOCKET.NextPtr]
2012
 
2013
        mov     [eax + SOCKET.PrevPtr], net_sockets
2014
        mov     [eax + SOCKET.NextPtr], ebx
2015
 
2016
        test    ebx, ebx
2017
        jz      @f
2018
 
2019
        pusha
2020
        lea     ecx, [ebx + SOCKET.mutex]
2021
        call    mutex_lock
2022
        popa
2023
 
2024
        mov     [ebx + SOCKET.PrevPtr], eax
2025
 
2026
        pusha
2027
        lea     ecx, [ebx + SOCKET.mutex]
2028
        call    mutex_unlock
2029
        popa
2030
       @@:
2031
 
2032
        mov     [net_sockets + SOCKET.NextPtr], eax
2033
        or      eax, eax                ; used to clear zero flag
3647 hidnplayr 2034
 
2035
        pusha
2036
        mov     ecx, socket_mutex
2037
        call    mutex_unlock
2038
        popa
2039
 
3545 hidnplayr 2040
  .exit:
2041
        pop     ebx
2042
 
2043
        ret
2044
 
3658 hidnplayr 2045
  .not_yet:
2046
        mov     dword[esp+24], ENOTCONN
2047
        mov     dword[esp+32], -1
2048
        ret
3545 hidnplayr 2049
 
3658 hidnplayr 2050
 
3545 hidnplayr 2051
;----------------------------------------------------
2052
;
2053
; SOCKET_free
2054
;
2055
; Free socket data memory and remove socket from the list
2056
;
2057
; IN:  eax = socket ptr
2058
; OUT: /
2059
;
2060
;----------------------------------------------------
2061
align 4
2062
SOCKET_free:
2063
 
3556 hidnplayr 2064
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_free: %x\n", eax
3545 hidnplayr 2065
 
3652 hidnplayr 2066
        pusha
2067
        mov     ecx, socket_mutex
2068
        call    mutex_lock
2069
        popa
2070
 
3545 hidnplayr 2071
        call    SOCKET_check
2072
        jz      .error
2073
 
2074
        push    ebx
2075
 
2076
        pusha
2077
        lea     ecx, [eax + SOCKET.mutex]
2078
        call    mutex_lock
2079
        popa
2080
 
2081
        cmp     [eax + SOCKET.Domain], AF_INET4
2082
        jnz     .no_tcp
2083
 
2084
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
2085
        jnz     .no_tcp
2086
 
2087
        mov     ebx, eax
2088
        stdcall kernel_free, [ebx + STREAM_SOCKET.rcv.start_ptr]
2089
        stdcall kernel_free, [ebx + STREAM_SOCKET.snd.start_ptr]
2090
        mov     eax, ebx
2091
  .no_tcp:
2092
 
3652 hidnplayr 2093
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_free: freeing socket %x\n", eax
3545 hidnplayr 2094
        push    eax                             ; this will be passed to kernel_free
2095
        mov     ebx, [eax + SOCKET.NextPtr]
2096
        mov     eax, [eax + SOCKET.PrevPtr]
2097
 
3556 hidnplayr 2098
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_free: linking socket %x to socket %x\n", eax, ebx
3545 hidnplayr 2099
 
2100
        test    eax, eax
2101
        jz      @f
2102
        mov     [eax + SOCKET.NextPtr], ebx
2103
       @@:
2104
 
2105
        test    ebx, ebx
2106
        jz      @f
2107
        mov     [ebx + SOCKET.PrevPtr], eax
2108
       @@:
2109
 
2110
        call    kernel_free
2111
        pop     ebx
2112
 
3652 hidnplayr 2113
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_free: success!\n"
2114
 
2115
  .error:
2116
 
3647 hidnplayr 2117
        pusha
2118
        mov     ecx, socket_mutex
2119
        call    mutex_unlock
2120
        popa
2121
 
3545 hidnplayr 2122
        ret
2123
 
2124
;------------------------------------
2125
;
2126
; SOCKET_fork
2127
;
2128
; Create a child socket
2129
;
2130
; IN:  socket nr in ebx
2131
; OUT: child socket nr in eax
2132
;
2133
;-----------------------------------
2134
align 4
2135
SOCKET_fork:
2136
 
3556 hidnplayr 2137
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_fork: %x\n", ebx
3545 hidnplayr 2138
 
2139
; Exit if backlog queue is full
2140
        mov     eax, [ebx + SOCKET_QUEUE_LOCATION + queue.size]
2141
        cmp     ax, [ebx + SOCKET.backlog]
2142
        jae     .fail
2143
 
2144
; Allocate new socket
2145
        push    ebx
2146
        call    SOCKET_alloc
2147
        pop     ebx
2148
        jz      .fail
2149
 
2150
        push    eax
2151
        mov     esi, esp
2152
        add_to_queue (ebx + SOCKET_QUEUE_LOCATION), MAX_backlog, 4, .fail2
2153
        pop     eax
2154
 
2155
; Copy structure from current socket to new
2156
; We start at PID to preserve the socket num, and the 2 pointers at beginning of socket
2157
        lea     esi, [ebx + SOCKET.PID]
2158
        lea     edi, [eax + SOCKET.PID]
2159
        mov     ecx, (SOCKET_QUEUE_LOCATION - SOCKET.PID + 3)/4
2160
        rep     movsd
2161
 
2162
        and     [eax + SOCKET.options], not SO_ACCEPTCON
2163
 
2164
        ret
2165
 
2166
  .fail2:
2167
        add     esp, 4+4+4
2168
  .fail:
3556 hidnplayr 2169
        DEBUGF  DEBUG_NETWORK_ERROR, "SOCKET_fork: failed\n"
3545 hidnplayr 2170
        xor     eax, eax
2171
        ret
2172
 
2173
 
2174
;---------------------------------------------------
2175
;
2176
; SOCKET_num_to_ptr
2177
;
2178
; Get socket structure address by its number
2179
;
2180
; IN:  ecx = socket number
2181
; OUT: eax = 0 on error, socket ptr otherwise
2182
;       ZF = set on error
2183
;
2184
;---------------------------------------------------
2185
align 4
2186
SOCKET_num_to_ptr:
2187
 
3556 hidnplayr 2188
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_num_to_ptr: num=%u ", ecx
3545 hidnplayr 2189
 
3647 hidnplayr 2190
        pusha
2191
        mov     ecx, socket_mutex
2192
        call    mutex_lock
2193
        popa
2194
 
3545 hidnplayr 2195
        mov     eax, net_sockets
2196
 
2197
  .next_socket:
2198
        mov     eax, [eax + SOCKET.NextPtr]
2199
        or      eax, eax
2200
        jz      .error
2201
        cmp     [eax + SOCKET.Number], ecx
2202
        jne     .next_socket
2203
 
2204
        test    eax, eax
2205
 
3647 hidnplayr 2206
        pusha
2207
        mov     ecx, socket_mutex
2208
        call    mutex_unlock
2209
        popa
2210
 
3556 hidnplayr 2211
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ptr=%x\n", eax
3545 hidnplayr 2212
        ret
2213
 
2214
  .error:
3647 hidnplayr 2215
        pusha
2216
        mov     ecx, socket_mutex
2217
        call    mutex_unlock
2218
        popa
2219
 
3637 hidnplayr 2220
        DEBUGF  DEBUG_NETWORK_ERROR, "SOCKET_num_to_ptr: not found\n", eax
3545 hidnplayr 2221
        ret
2222
 
2223
 
2224
;---------------------------------------------------
2225
;
2226
; SOCKET_ptr_to_num
2227
;
2228
; Get socket number by its address
2229
;
2230
; IN:  eax = socket ptr
2231
; OUT: eax = 0 on error, socket num otherwise
2232
;       ZF = set on error
2233
;
2234
;---------------------------------------------------
2235
align 4
2236
SOCKET_ptr_to_num:
2237
 
3556 hidnplayr 2238
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ptr_to_num: ptr=%x ", eax
3545 hidnplayr 2239
 
2240
        call    SOCKET_check
2241
        jz      .error
2242
 
2243
        mov     eax, [eax + SOCKET.Number]
2244
 
3556 hidnplayr 2245
        DEBUGF  DEBUG_NETWORK_VERBOSE, "num=%u\n", eax
3545 hidnplayr 2246
        ret
2247
 
2248
  .error:
3556 hidnplayr 2249
        DEBUGF  DEBUG_NETWORK_ERROR, "SOCKET_ptr_to_num: not found\n", eax
3545 hidnplayr 2250
        ret
2251
 
2252
 
2253
;---------------------------------------------------
2254
;
2255
; SOCKET_check
2256
;
2257
; checks if the given value is really a socket ptr
2258
;
2259
; IN:  eax = socket ptr
2260
; OUT: eax = 0 on error, unchanged otherwise
2261
;       ZF = set on error
2262
;
2263
;---------------------------------------------------
2264
align 4
2265
SOCKET_check:
2266
 
3556 hidnplayr 2267
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_check: %x\n", eax
3545 hidnplayr 2268
 
2269
        push    ebx
2270
        mov     ebx, net_sockets
2271
 
2272
  .next_socket:
2273
        mov     ebx, [ebx + SOCKET.NextPtr]
2274
        or      ebx, ebx
2275
        jz      .done
2276
        cmp     ebx, eax
2277
        jnz     .next_socket
2278
 
2279
  .done:
2280
        mov     eax, ebx
2281
        test    eax, eax
2282
        pop     ebx
2283
 
2284
        ret
2285
 
2286
 
2287
 
2288
;---------------------------------------------------
2289
;
2290
; SOCKET_check_owner
2291
;
2292
; checks if the caller application owns the socket
2293
;
2294
; IN:  eax = socket ptr
2295
; OUT:  ZF = true/false
2296
;
2297
;---------------------------------------------------
2298
align 4
2299
SOCKET_check_owner:
2300
 
3556 hidnplayr 2301
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_check_owner: %x\n", eax
3545 hidnplayr 2302
 
2303
        push    ebx
2304
        mov     ebx, [TASK_BASE]
2305
        mov     ebx, [ebx + TASKDATA.pid]
2306
        cmp     [eax + SOCKET.PID], ebx
2307
        pop      ebx
2308
 
2309
        ret
2310
 
2311
 
2312
 
2313
 
2314
;------------------------------------------------------
2315
;
2316
; SOCKET_process_end
2317
;
2318
; Kernel calls this function when a certain process ends
2319
; This function will check if the process had any open sockets
2320
; And update them accordingly
2321
;
2322
; IN:  edx = pid
2323
; OUT: /
2324
;
2325
;------------------------------------------------------
2326
align 4
2327
SOCKET_process_end:
2328
 
3648 hidnplayr 2329
        pushf
2330
        cli     ; FIXME
2331
 
3556 hidnplayr 2332
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_process_end: %x\n", edx
3545 hidnplayr 2333
 
3647 hidnplayr 2334
        pusha
2335
        mov     ecx, socket_mutex
2336
        call    mutex_lock
2337
        popa
2338
 
3545 hidnplayr 2339
        push    ebx
2340
        mov     ebx, net_sockets
2341
 
2342
  .next_socket:
2343
        mov     ebx, [ebx + SOCKET.NextPtr]
2344
  .next_socket_test:
2345
        test    ebx, ebx
2346
        jz      .done
2347
 
2348
        cmp     [ebx + SOCKET.PID], edx
2349
        jne     .next_socket
2350
 
3556 hidnplayr 2351
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_process_end: killing socket %x\n", ebx
3545 hidnplayr 2352
 
2353
        mov     [ebx + SOCKET.PID], 0
2354
        mov     eax, ebx
2355
        mov     ebx, [ebx + SOCKET.NextPtr]
3648 hidnplayr 2356
 
3545 hidnplayr 2357
        pusha
3648 hidnplayr 2358
        mov     ecx, socket_mutex
2359
        call    mutex_unlock
2360
        popa
2361
 
2362
        pusha
3652 hidnplayr 2363
        cmp     [eax + SOCKET.Domain], AF_INET4
2364
        jne     .free
2365
 
2366
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
2367
        jne     .free
2368
 
2369
        call    TCP_close
2370
        jmp     .closed
2371
 
2372
  .free:
2373
        call    SOCKET_free
2374
 
2375
  .closed:
3545 hidnplayr 2376
        popa
3648 hidnplayr 2377
 
2378
        pusha
2379
        mov     ecx, socket_mutex
2380
        call    mutex_lock
2381
        popa
2382
 
3545 hidnplayr 2383
        jmp     .next_socket_test
2384
 
2385
  .done:
2386
        pop     ebx
2387
 
3647 hidnplayr 2388
        pusha
2389
        mov     ecx, socket_mutex
2390
        call    mutex_unlock
2391
        popa
2392
 
3648 hidnplayr 2393
        popf
2394
 
3545 hidnplayr 2395
        ret
2396
 
2397
 
2398
 
2399
 
2400
;-----------------------------------------------------------------
2401
;
2402
; SOCKET_is_connecting
2403
;
2404
;  IN:  eax = socket ptr
2405
;  OUT: /
2406
;
2407
;-----------------------------------------------------------------
2408
 
2409
align 4
2410
SOCKET_is_connecting:
2411
 
3556 hidnplayr 2412
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_is_connecting: %x\n", eax
3545 hidnplayr 2413
 
2414
        and     [eax + SOCKET.options], not (SS_ISCONNECTED + SS_ISDISCONNECTING + SS_ISCONFIRMING)
2415
        or      [eax + SOCKET.options], SS_ISCONNECTING
2416
 
2417
        jmp     SOCKET_notify
2418
 
2419
 
2420
 
2421
;-----------------------------------------------------------------
2422
;
2423
; SOCKET_is_connected
2424
;
2425
;  IN:  eax = socket ptr
2426
;  OUT: /
2427
;
2428
;-----------------------------------------------------------------
2429
 
2430
align 4
2431
SOCKET_is_connected:
2432
 
3556 hidnplayr 2433
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_is_connected: %x\n", eax
3545 hidnplayr 2434
 
2435
        and     [eax + SOCKET.options], not (SS_ISCONNECTING + SS_ISDISCONNECTING + SS_ISCONFIRMING)
2436
        or      [eax + SOCKET.options], SS_ISCONNECTED
2437
 
2438
        jmp     SOCKET_notify
2439
 
2440
 
2441
 
2442
 
2443
;-----------------------------------------------------------------
2444
;
2445
; SOCKET_is_disconnecting
2446
;
2447
;  IN:  eax = socket ptr
2448
;  OUT: /
2449
;
2450
;-----------------------------------------------------------------
2451
 
2452
align 4
2453
SOCKET_is_disconnecting:
2454
 
3556 hidnplayr 2455
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_is_disconnecting: %x\n", eax
3545 hidnplayr 2456
 
2457
        and     [eax + SOCKET.options], not (SS_ISCONNECTING)
2458
        or      [eax + SOCKET.options], SS_ISDISCONNECTING + SS_CANTRCVMORE + SS_CANTSENDMORE
2459
 
2460
        jmp     SOCKET_notify
2461
 
2462
 
2463
 
2464
;-----------------------------------------------------------------
2465
;
2466
; SOCKET_is_disconnected
2467
;
2468
;  IN:  eax = socket ptr
2469
;  OUT: /
2470
;
2471
;-----------------------------------------------------------------
2472
 
2473
align 4
2474
SOCKET_is_disconnected:
2475
 
3556 hidnplayr 2476
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_is_disconnected: %x\n", eax
3545 hidnplayr 2477
 
2478
        and     [eax + SOCKET.options], not (SS_ISCONNECTING + SS_ISCONNECTED + SS_ISDISCONNECTING)
2479
        or      [eax + SOCKET.options], SS_CANTRCVMORE + SS_CANTSENDMORE
2480
 
2481
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
2482
        je      .tcp
2483
 
2484
        cmp     [eax + SOCKET.Protocol], IP_PROTO_UDP
2485
        je      .udp
2486
 
2487
        jmp     SOCKET_notify
2488
 
2489
  .tcp:
2490
  .udp:
2491
        mov     [eax + UDP_SOCKET.LocalPort], 0         ; UDP and TCP structs store localport at the same offset
2492
        mov     [eax + UDP_SOCKET.RemotePort], 0
2493
 
2494
        jmp     SOCKET_notify
2495
 
2496
 
2497
;-----------------------------------------------------------------
2498
;
2499
; SOCKET_cant_recv_more
2500
;
2501
;  IN:  eax = socket ptr
2502
;  OUT: /
2503
;
2504
;-----------------------------------------------------------------
2505
 
2506
align 4
2507
SOCKET_cant_recv_more:
2508
 
3556 hidnplayr 2509
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_cant_recv_more: %x\n", eax
3545 hidnplayr 2510
 
2511
        or      [eax + SOCKET.options], SS_CANTRCVMORE
2512
 
3565 hidnplayr 2513
        call    SOCKET_notify
2514
 
3545 hidnplayr 2515
        ret
2516
 
2517
 
2518
 
2519
;-----------------------------------------------------------------
2520
;
2521
; SOCKET_cant_send_more
2522
;
2523
;  IN:  eax = socket ptr
2524
;  OUT: /
2525
;
2526
;-----------------------------------------------------------------
2527
 
2528
align 4
2529
SOCKET_cant_send_more:
2530
 
3556 hidnplayr 2531
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_cant_send_more: %x\n", eax
3545 hidnplayr 2532
 
2533
        or      [eax + SOCKET.options], SS_CANTSENDMORE
3658 hidnplayr 2534
        mov     [eax + SOCKET.snd_proc], .notconn
3545 hidnplayr 2535
 
3565 hidnplayr 2536
        call    SOCKET_notify
2537
 
3658 hidnplayr 2538
        ret
2539
 
2540
  .notconn:
2541
        mov     dword[esp+24], ENOTCONN
2542
        mov     dword[esp+32], -1
3545 hidnplayr 2543
        ret