Subversion Repositories Kolibri OS

Rev

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