Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
1159 hidnplayr 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                 ;;
1196 hidnplayr 3
;; Copyright (C) KolibriOS team 2004-2009. All rights reserved.    ;;
1159 hidnplayr 4
;; Distributed under terms of the GNU General Public License       ;;
5
;;                                                                 ;;
6
;;  SOCKET.INC                                                     ;;
7
;;                                                                 ;;
8
;;                                                                 ;;
9
;;    Written by hidnplayr@kolibrios.org                           ;;
10
;;    based on code by mike.dld                                    ;;
11
;;                                                                 ;;
12
;;          GNU GENERAL PUBLIC LICENSE                             ;;
13
;;             Version 2, June 1991                                ;;
14
;;                                                                 ;;
15
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
16
 
1206 hidnplayr 17
$Revision: 1208 $
1159 hidnplayr 18
 
19
align 4
20
struct	 SOCKET
21
	 .PrevPtr		dd ? ; pointer to previous socket in list
22
	 .NextPtr		dd ? ; pointer to next socket in list
23
	 .Number		dd ? ; socket number (unique within single process)
24
	 .PID			dd ? ; application process id
25
	 .Domain		dd ? ; INET/UNIX/..
26
	 .Type			dd ? ; RAW/UDP/TCP/...
1196 hidnplayr 27
	 .Protocol		dd ? ; ICMP/IPv4/ARP/
1159 hidnplayr 28
	 .LocalIP		dd ? ; local IP address
29
	 .RemoteIP		dd ? ; remote IP address
1206 hidnplayr 30
	 .LocalPort		dw ? ; local port       (In INET byte order)
31
	 .RemotePort		dw ? ; remote port      (IN INET byte order
1196 hidnplayr 32
	 .OrigRemoteIP		dd ? ; original remote IP address (used to reset to LISTEN state)
33
	 .OrigRemotePort	dw ? ; original remote port (used to reset to LISTEN state)
1159 hidnplayr 34
	 .rxDataCount		dd ? ; rx data count
1196 hidnplayr 35
	 .TCBState		dd ? ; TCB state
36
	 .TCBTimer		dd ? ; TCB timer (seconds)
37
	 .ISS			dd ? ; initial send sequence
38
	 .IRS			dd ? ; initial receive sequence
39
	 .SND_UNA		dd ? ; sequence number of unack'ed sent Packets
40
	 .SND_NXT		dd ? ; bext send sequence number to use
41
	 .SND_WND		dd ? ; send window
42
	 .RCV_NXT		dd ? ; next receive sequence number to use
43
	 .RCV_WND		dd ? ; receive window
44
	 .SEG_LEN		dd ? ; segment length
45
	 .SEG_WND		dd ? ; segment window
1159 hidnplayr 46
	 .wndsizeTimer		dd ? ; window size timer
47
	 .lock			dd ? ; lock mutex
48
	 .backlog		dw ? ; Backlog
49
	 .rxData:		     ; receive data buffer here
50
ends
51
 
52
MAX_backlog	equ 20
53
 
54
; socket buffers
55
SOCKETBUFFSIZE		equ 4096  ; state + config + buffer.
56
SOCKETHEADERSIZE	equ SOCKET.rxData ; thus 4096 - SOCKETHEADERSIZE bytes data
57
 
58
uglobal
59
	net_sockets	rd 2
60
	last_UDP_port	dw ? ; These values give the number of the last used ephemeral port
61
	last_TCP_port	dw ? ;
62
endg
63
 
64
 
65
;-----------------------------------------------
66
;
67
; SOCKET_init
68
;
69
;  -
70
;
71
;  IN:  /
72
;  OUT: /
73
;
74
;-----------------------------------------------
75
 
76
align 4
77
socket_init:
78
 
79
	mov	[net_sockets], 0
80
	mov	[net_sockets + 4], 0
81
 
82
	mov	[last_UDP_port], MIN_EPHEMERAL_PORT
83
	mov	[last_TCP_port], MIN_EPHEMERAL_PORT
84
 
85
	ret
86
 
87
 
88
;-----------------------------------------------------------------------------
89
;
90
; Socket API (function 74)
91
;
92
;-----------------------------------------------------------------------------
93
 
94
align 4
95
sys_socket:
96
 
97
	test	bl, bl
98
	jz	socket_open	; 0
99
	dec	bl
100
	jz	socket_close	; 1
101
	dec	bl
102
	jz	socket_bind	; 2
103
	dec	bl
104
	jz	socket_listen	; 3
105
	dec	bl
106
	jz	socket_connect	; 4
107
	dec	bl
108
	jz	socket_accept	; 5
109
	dec	bl
110
	jz	socket_send	; 6
111
	dec	bl
112
	jz	socket_recv	; 7
113
 
1185 hidnplayr 114
s_error:
1159 hidnplayr 115
	mov	dword [esp+32],-1
116
 
117
	ret
118
 
119
 
120
 
121
 
122
;-----------------------------------------------
123
;
124
; SOCKET_open
125
;
126
;
127
;  IN:  domain in ecx
128
;       type in edx
1196 hidnplayr 129
;       protocol in esi
1159 hidnplayr 130
;  OUT: eax is socket num, -1 on error
131
;
132
;-----------------------------------------------
1206 hidnplayr 133
align 4
1159 hidnplayr 134
socket_open:
135
 
136
	DEBUGF	1,"socket_open: domain: %u, type: %u",ecx, edx
137
 
138
	call	net_socket_alloc
139
	or	eax, eax
1185 hidnplayr 140
	jz	s_error
1159 hidnplayr 141
 
142
	mov	[eax + SOCKET.Domain], ecx
143
	mov	[eax + SOCKET.Type], edx
1196 hidnplayr 144
	mov	[eax + SOCKET.Protocol], esi
1159 hidnplayr 145
 
146
	stdcall net_socket_addr_to_num, eax
147
	DEBUGF	1,", socketnumber: %u\n", eax
148
 
149
	mov	[esp+32], eax
150
 
151
	ret
152
 
153
 
154
 
155
 
156
;-----------------------------------------------
157
;
158
; SOCKET_bind
159
;
160
;  IN:  socket number in ecx
161
;       pointer to sockaddr struct in edx
162
;       length of that struct in esi
163
;  OUT: 0 on success
164
;
165
;-----------------------------------------------
1206 hidnplayr 166
align 4
1159 hidnplayr 167
socket_bind:
168
 
169
	DEBUGF	1,"Socket_bind: socknum: %u sockaddr: %x, length: %u, ",ecx,edx,esi
170
 
171
	stdcall net_socket_num_to_addr, ecx
172
	cmp	eax, -1
1185 hidnplayr 173
	jz	s_error
1159 hidnplayr 174
 
175
	cmp	esi, 2
1185 hidnplayr 176
	jl	s_error
1159 hidnplayr 177
 
178
	cmp	word [edx], AF_INET4
1206 hidnplayr 179
	jne	s_error
1159 hidnplayr 180
 
181
  .af_inet4:
182
 
183
	cmp	esi, 6
1185 hidnplayr 184
	jl	s_error
1159 hidnplayr 185
 
1206 hidnplayr 186
	mov	ecx, [eax + SOCKET.Type]
1159 hidnplayr 187
	mov	bx, word [edx + 2]
1206 hidnplayr 188
	DEBUGF	1,"local port: %x ",bx
1159 hidnplayr 189
	test	bx, bx
1206 hidnplayr 190
	jz	.find_free
1159 hidnplayr 191
 
1206 hidnplayr 192
	call	socket_check_port
193
	test	bx, bx
194
	je	s_error
195
	jmp	.got_port
1159 hidnplayr 196
 
1206 hidnplayr 197
  .find_free:
1159 hidnplayr 198
 
1206 hidnplayr 199
	call	socket_find_port
200
	test	bx, bx
201
	je	s_error
1159 hidnplayr 202
 
1206 hidnplayr 203
  .got_port:
204
	DEBUGF	1,"using port: %x ",bx
1159 hidnplayr 205
	mov	word [eax + SOCKET.LocalPort], bx
206
 
207
	mov	ebx, dword [edx + 4]
208
	mov	dword [eax + SOCKET.LocalIP], ebx
209
 
210
	DEBUGF	1,"local ip: %u.%u.%u.%u\n",\
211
	[eax + SOCKET.LocalIP]:1,[eax + SOCKET.LocalIP + 1]:1,[eax + SOCKET.LocalIP + 2]:1,[eax + SOCKET.LocalIP + 3]:1
212
 
213
	mov	dword [esp+32],0
214
	ret
215
 
216
 
217
 
218
 
219
;-----------------------------------------------
220
;
221
; SOCKET_connect
222
;
223
;
224
;  IN:  socket number in ecx
225
;       pointer to sockaddr struct in edx
226
;       length of that struct in esi
227
;  OUT: 0 on success
228
;
229
;-----------------------------------------------
230
align 4
231
socket_connect:
232
 
233
	DEBUGF	1,"Socket_connect: socknum: %u sockaddr: %x, length: %u,",ecx,edx,esi
234
 
235
	stdcall net_socket_num_to_addr, ecx
236
	cmp	eax, -1
1185 hidnplayr 237
	jz	s_error
1159 hidnplayr 238
 
239
	cmp	esi, 2
1185 hidnplayr 240
	jl	s_error
1159 hidnplayr 241
 
242
	cmp	word [edx], AF_INET4
243
	je	.af_inet4
244
 
1185 hidnplayr 245
	jmp	s_error
1159 hidnplayr 246
 
247
  .af_inet4:
248
 
249
	cmp	esi, 8
1185 hidnplayr 250
	jl	s_error
1159 hidnplayr 251
 
252
	cmp	[eax + SOCKET.Type], IP_PROTO_UDP
253
	je	.udp
254
 
255
	cmp	[eax + SOCKET.Type], IP_PROTO_ICMP
256
	je	.icmp
257
 
1206 hidnplayr 258
	cmp	[eax + SOCKET.Type], IP_PROTO_TCP
259
	je	.tcp
1159 hidnplayr 260
 
1185 hidnplayr 261
	jmp	s_error
1159 hidnplayr 262
 
263
  .udp:
264
 
265
	mov	bx , word [edx + 2]
266
	mov	word [eax + SOCKET.RemotePort], bx
1206 hidnplayr 267
	DEBUGF	1,"remote port: %x ",bx
1159 hidnplayr 268
 
269
	mov	ebx, dword [edx + 4]
270
	mov	dword [eax + SOCKET.RemoteIP], ebx
271
	DEBUGF	1,"remote ip: %u.%u.%u.%u\n",[edx+4]:1,[edx+5]:1,[edx+6]:1,[edx+7]:1
272
 
273
	mov	dword [esp+32],0
274
	ret
275
 
276
  .icmp:
277
 
278
 
279
	ret
280
 
281
 
282
 
283
  .tcp:
284
 
285
;local sockAddr dd ?
286
 
287
;        cmp     esi, SOCKET_PASSIVE
288
;        jne     .skip_port_check
289
;
290
;        push    ebx
291
;        mov     eax, ebx
292
;        xchg    al, ah
293
;        mov     ebx, net_sockets
294
;
295
;  .next_socket:
296
;        mov     ebx, [ebx + SOCKET.NextPtr]
297
;        or      ebx, ebx
298
;        jz      .last_socket
299
;        cmp     [ebx + SOCKET.TCBState], TCB_LISTEN
300
;        jne     .next_socket
301
;        cmp     [ebx + SOCKET.LocalPort], ax
302
;        jne     .next_socket
303
;
304
;        xchg    al, ah
305
;        DEBUGF  1, "K : error: port %u is listened by 0x%x\n", ax, ebx
306
;        pop     ebx
307
;        jmp     .error
308
;
309
;  .last_socket:
310
;        pop     ebx
311
;
312
;  .skip_port_check:
313
 
314
;        mov     [eax + SOCKET.wndsizeTimer], 0     ; Reset the window timer.
315
;
316
;        xchg    bh, bl
317
;        mov     [eax + SOCKET.LocalPort], bx
318
;        xchg    ch, cl
319
;        mov     [eax + SOCKET.RemotePort], cx
320
;        mov     [eax + SOCKET.OrigRemotePort], cx
321
;        mov     ebx, [IP_LIST]
322
;        mov     [eax + SOCKET.LocalIP], ebx
323
;        mov     [eax + SOCKET.RemoteIP], edx
324
;        mov     [eax + SOCKET.OrigRemoteIP], edx
325
 
326
;        mov     ebx, TCB_LISTEN
327
;        cmp     esi, SOCKET_PASSIVE
328
;        je      @f
329
;        mov     ebx, TCB_SYN_SENT
330
;    @@: mov     [eax + SOCKET.TCBState], ebx            ; Indicate the state of the TCB
331
 
332
;        cmp     ebx, TCB_LISTEN
333
;        je      .exit
334
 
335
	; Now, if we are in active mode, then we have to send a SYN to the specified remote port
336
;        mov     eax, EMPTY_QUEUE
337
;        call    dequeue
338
;        cmp     ax, NO_BUFFER
339
;        je      .exit
340
 
341
;        push    eax
342
 
343
;        mov     bl, TH_SYN
344
;        xor     ecx, ecx
345
;        stdcall build_tcp_Packet, [sockAddr]
346
 
347
;        mov     eax, NET1OUT_QUEUE
348
;        mov     edx, [IP_LIST]
349
;        mov     ecx, [sockAddr]
350
;        cmp     edx, [ecx + SOCKET.RemoteIP]
351
;        jne     .not_local
352
;        mov     eax, IPIN_QUEUE
353
 
354
;  .not_local:
355
	; Send it.
356
;        pop     ebx
357
;        call    queue
358
 
359
  .exit:
360
	xor	eax, eax
361
	ret
362
 
363
 
364
 
365
 
366
;-----------------------------------------------
367
;
368
; SOCKET_listen
369
;
370
;
371
;  IN:  socket number in ecx
372
;       backlog in edx
373
;  OUT: eax is socket num, -1 on error
374
;
375
;-----------------------------------------------
1206 hidnplayr 376
align 4
1159 hidnplayr 377
socket_listen:
378
 
379
	DEBUGF	1,"Socket_listen: socknum: %u backlog: %u\n",ecx,edx
380
 
381
	stdcall net_socket_num_to_addr, ecx
382
	cmp	eax, -1
1185 hidnplayr 383
	jz	s_error
1159 hidnplayr 384
 
385
	cmp	edx, MAX_backlog
386
	jl	.ok
387
	mov	dx , 20
388
  .ok:
389
 
390
	mov	[eax + SOCKET.backlog], dx
391
 
392
	; TODO: insert code for active connections like TCP
393
 
394
	mov	dword [esp+32], 0
395
	ret
396
 
397
 
398
 
399
 
400
 
401
 
402
;-----------------------------------------------
403
;
404
; SOCKET_accept
405
;
406
;
407
;  IN:  socket number in ecx
408
;       addr in edx
409
;       addrlen in esi
410
;  OUT: eax is socket num, -1 on error
411
;
412
;-----------------------------------------------
1206 hidnplayr 413
align 4
1159 hidnplayr 414
socket_accept:
415
 
416
	DEBUGF	1,"Socket_accept: socknum: %u sockaddr: %x, length: %u\n",ecx,edx,esi
417
 
418
	stdcall net_socket_num_to_addr, ecx
419
	or	eax, eax
1185 hidnplayr 420
	jz	s_error
1159 hidnplayr 421
	mov	esi, eax
422
 
423
	cmp	[esi + SOCKET.backlog], 0
1185 hidnplayr 424
	jz	s_error
1159 hidnplayr 425
 
426
	call	net_socket_alloc
427
	or	eax, eax
1185 hidnplayr 428
	jz	s_error
1159 hidnplayr 429
	mov	edi, eax
430
 
431
	dec	[esi + SOCKET.backlog]
432
 
433
	mov	ecx, (SOCKET.rxData+3)/4
434
	rep	movsd
435
 
436
	mov	[edi + SOCKET.backlog], 0
437
 
438
	; TODO: fill in structure in ecx
439
 
440
	mov	[esi + SOCKET.RemoteIP], 0
441
	mov	[esi + SOCKET.RemotePort], 0
442
 
443
	stdcall net_socket_addr_to_num, eax
444
	mov	[esp+32], eax
445
 
446
	ret
447
 
448
 
449
 
450
;-----------------------------------------------
451
;
452
; SOCKET_close
453
;
454
;
455
;  IN:  socket number in ecx
456
;  OUT: eax is socket num, -1 on error
457
;
458
;-----------------------------------------------
1206 hidnplayr 459
align 4
1159 hidnplayr 460
socket_close:
461
 
462
	DEBUGF	1,"Socket_close: socknum: %u\n",ecx
463
 
464
	stdcall net_socket_num_to_addr, ecx
465
	or	eax, eax
1185 hidnplayr 466
	jz	s_error
1159 hidnplayr 467
 
468
 
469
	cmp	[eax + SOCKET.Type], IP_PROTO_UDP
470
	je	.udp
471
 
472
	cmp	[eax + SOCKET.Type], IP_PROTO_ICMP
473
	je	.icmp
474
 
1206 hidnplayr 475
	cmp	[eax + SOCKET.Type], IP_PROTO_TCP
476
	je	.tcp
1159 hidnplayr 477
 
1185 hidnplayr 478
	jmp	s_error
1159 hidnplayr 479
 
480
  .udp:
481
 
482
	lea	ebx, [eax + SOCKET.lock]
483
	call	wait_mutex
484
	; TODO: mark the socket for deletion, using the mutex
485
 
486
	stdcall net_socket_free, eax
487
 
488
	mov	dword [esp+32],0
489
	ret
490
 
491
 
492
  .icmp:
493
 
494
 
495
 
496
	ret
497
 
498
  .tcp:
499
 
500
if 1 = 0
501
;local sockAddr dd ?
502
 
503
;        DEBUGF  1, "K : socket_close_tcp (0x%x)\n", ebx
504
	; first, remove any resend entries
505
	pusha
506
 
507
	mov	esi, resendQ
508
	mov	ecx, 0
509
 
510
  .next_resendq:
511
	cmp	ecx, NUMRESENDENTRIES
512
	je	.last_resendq	    ; None left
513
	cmp	[esi + 4], ebx
514
	je	@f		    ; found one
515
	inc	ecx
516
	add	esi, 8
517
	jmp	.next_resendq
518
 
519
    @@: mov	dword[esi + 4], 0
520
	inc	ecx
521
	add	esi, 8
522
	jmp	.next_resendq
523
 
524
  .last_resendq:
525
	popa
526
 
527
	mov	ebx, eax
528
;        mov     [sockAddr], eax
529
 
530
	cmp	[eax + SOCKET.TCBState], TCB_LISTEN
531
	je	.destroy_tcb
532
	cmp	[eax + SOCKET.TCBState], TCB_SYN_SENT
533
	je	.destroy_tcb
534
 
535
; Now construct the response, and queue for sending by IP
536
	mov	eax, EMPTY_QUEUE
537
	call	dequeue
538
	cmp	ax, NO_BUFFER
539
	je	.error
540
 
541
	push	eax
542
 
543
	mov	bl, TH_FIN
544
	xor	ecx, ecx
545
	xor	esi, esi
546
	stdcall build_tcp_Packet, [sockAddr]
547
 
548
	mov	 ebx, [sockAddr]
549
	; increament SND.NXT in socket
550
	lea	esi, [ebx + SOCKET.SND_NXT]
551
	call	inc_inet_esi
552
 
553
	; Get the socket state
554
	mov	eax, [ebx + SOCKET.TCBState]
555
	cmp	eax, TCB_SYN_RECEIVED
556
	je	.fin_wait_1
557
	cmp	eax, TCB_ESTABLISHED
558
	je	.fin_wait_1
559
 
560
	; assume CLOSE WAIT
561
	; Send a fin, then enter last-ack state
562
	mov	[ebx + SOCKET.TCBState], TCB_LAST_ACK
563
	jmp	.send
564
 
565
  .fin_wait_1:
566
	; Send a fin, then enter finwait2 state
567
	mov	[ebx + SOCKET.TCBState], TCB_FIN_WAIT_1
568
 
569
  .send:
570
	mov	eax, NET1OUT_QUEUE
571
	mov	edx, [IP_LIST]
572
;        mov     ecx, [sockAddr]
573
	cmp	edx, [ecx + SOCKET.RemoteIP]
574
	jne	.not_local
575
	mov	eax, IPIN_QUEUE
576
 
577
  .not_local:
578
	; Send it.
579
	pop	ebx
580
	call	queue
581
	jmp	.exit
582
 
583
 
584
  .destroy_tcb:
585
 
586
	stdcall net_socket_free, eax
587
 
588
end if
589
 
590
  .exit:
591
	mov	dword [esp+32],0
592
	ret
593
 
594
 
595
 
596
 
597
;-----------------------------------------------
598
;
599
; SOCKET_receive
600
;
601
;
602
;  IN:  socket number in ecx
603
;       addr in edx
604
;       addrlen in esi
605
;       flags in edi
606
;  OUT: eax is number of bytes copied, -1 on error
607
;
608
;-----------------------------------------------
1206 hidnplayr 609
align 4
1159 hidnplayr 610
socket_recv:
611
 
612
	DEBUGF	1,"Socket_receive: socknum: %u sockaddr: %x, length: %u, flags: %x\n",ecx,edx,esi,edi
613
 
614
	stdcall net_socket_num_to_addr, ecx		   ; get real socket address
615
	or	eax, eax
1185 hidnplayr 616
	jz	s_error
1159 hidnplayr 617
 
618
	DEBUGF 1,"real socket address:%x\n", eax
619
 
620
	mov	dword[esp+32], -1
621
 
622
	mov	edi, edx
623
 
624
	lea	ebx, [eax + SOCKET.lock]
625
	call	wait_mutex
626
 
627
	mov	ecx, [eax + SOCKET.rxDataCount] 	   ; get count of bytes
628
	DEBUGF 1,"bytes in socket:%u\n", ecx
629
	test	ecx, ecx				   ; if count of bytes is zero..
630
	jz	.exit					   ; exit function (eax will be zero)
631
 
632
	cmp	ecx, esi				   ; if buffer size is larger then the bytes of data, copy all data
633
	jle	.copy_all_bytes
634
 
635
	sub	ecx, esi				   ; store new count (data bytes in buffer - bytes we're about to copy)
636
	mov	[eax + SOCKET.rxDataCount], ecx 	   ;
637
	push	ecx
638
	mov	edx, esi
639
 
640
	call	.start_copy				   ; copy to the application
641
 
642
	mov	dword[esp+32], edx
643
 
644
	lea	edi, [eax + SOCKET.rxData]		   ; Now shift the remaining bytes to start of buffer
645
	lea	esi, [edi + edx]
646
	mov	ecx, [esp]
647
	shr	ecx, 2					   ; divide eax by 4
648
	rep	movsd					   ; copy all full dwords
649
	pop	ecx
650
	and	ecx, 3
651
	rep	movsb					   ; copy remaining bytes
652
 
653
  .exit:
654
	mov	[eax + SOCKET.lock], 0
655
	ret
656
 
657
  .copy_all_bytes:
658
	mov	dword[esp+32], ecx
659
	mov	[eax + SOCKET.rxDataCount], 0		  ; store new count (zero)
660
	push	dword .exit				   ; this code results in same as commented out code
661
 
662
  .start_copy:
663
	DEBUGF	1,"copying %u bytes\n",ecx
664
 
665
	lea	esi, [eax + SOCKET.rxData]
666
	push	ecx
667
	shr	ecx, 2					   ; divide eax by 4
668
	rep	movsd
669
	pop	ecx
670
	and	ecx, 3
671
	rep	movsb					   ; copy the rest bytes
672
 
673
	ret						   ; exit, or go back to shift remaining bytes if any
674
 
675
 
676
 
677
;-----------------------------------------------
678
;
679
; SOCKET_send
680
;
681
;
682
;  IN:  socket number in ecx
1206 hidnplayr 683
;       pointer to data in edx
684
;       datalength in esi
1159 hidnplayr 685
;       flags in edi
686
;  OUT: -1 on error
687
;
688
;-----------------------------------------------
1206 hidnplayr 689
align 4
1159 hidnplayr 690
socket_send:
691
 
692
	DEBUGF	1,"Socket_send: socknum: %u sockaddr: %x, length: %u, flags: %x, ",ecx,edx,esi,edi
693
 
694
	stdcall net_socket_num_to_addr, ecx		   ; get real socket address
695
	or	eax, eax
1185 hidnplayr 696
	jz	s_error
1159 hidnplayr 697
 
1206 hidnplayr 698
	cmp	word [eax + SOCKET.Domain], AF_INET4
699
	je	.af_inet4
700
 
701
	jmp	s_error
702
 
703
  .af_inet4:
704
 
1159 hidnplayr 705
	DEBUGF	1,"Socket type:%u\n", [eax + SOCKET.Type]:4
706
 
707
	cmp	[eax + SOCKET.Type], IP_PROTO_UDP
708
	je	.udp
709
 
710
	cmp	[eax + SOCKET.Type], IP_PROTO_ICMP
711
	je	.icmp
712
 
1206 hidnplayr 713
	cmp	[eax + SOCKET.Type], IP_PROTO_TCP
714
	je	.tcp
1159 hidnplayr 715
 
1185 hidnplayr 716
	jmp	s_error
1159 hidnplayr 717
 
718
  .udp:
719
 
1206 hidnplayr 720
	DEBUGF	1,"type: UDP, "
1159 hidnplayr 721
 
1206 hidnplayr 722
	cmp	[eax + SOCKET.LocalPort],0
723
	jne	.port_ok
724
 
1208 hidnplayr 725
	push	esi
1206 hidnplayr 726
	mov	ecx, [eax + SOCKET.Type]
727
	call	socket_find_port
728
	test	bx, bx
1208 hidnplayr 729
	pop	esi
1206 hidnplayr 730
	je	s_error
731
	mov	[eax + SOCKET.LocalPort], bx
732
 
733
  .port_ok:
734
 
1159 hidnplayr 735
	mov	ecx, esi
736
	mov	esi, edx
737
	mov	edx, dword [eax + SOCKET.LocalPort] ; load local port and remote port at once
1208 hidnplayr 738
	DEBUGF	1,"local port: %x, remote port: %x\n",[eax + SOCKET.LocalPort]:4, [eax + SOCKET.RemotePort]:4
1159 hidnplayr 739
	mov	ebx, [eax + SOCKET.LocalIP]
740
	mov	eax, [eax + SOCKET.RemoteIP]
741
 
1196 hidnplayr 742
	call	UDP_create_packet
1159 hidnplayr 743
 
744
	mov	[esp+32], eax
745
	ret
746
 
747
  .icmp:
748
	; note: for ICMP sockets the SOCKET.LocalPort is used as the 'Identifier' value for ICMP packets
749
	; the application must add the header to the data, the kernel will fill in 'identifier' and 'checksum'
750
 
751
	sub	ecx, ICMP_Packet.Data
752
	mov	esi, edx
753
	push	ax
754
	call	IPv4_get_frgmnt_num
755
	mov	dx, ax
756
	pop	ax
757
	shl	edx, 16
758
	mov	dh , [esi + ICMP_Packet.Type]
759
	mov	dl , [esi + ICMP_Packet.Code]
760
	mov	di , [esi + ICMP_Packet.Identifier]
761
;        mov     [eax + SOCKET.LocalPort], di            ; Set localport to the identifier number, so we can receive reply's
762
	shl	edi, 16
763
	mov	di , [esi + ICMP_Packet.SequenceNumber]
764
	add	esi, ICMP_Packet.Data
765
	mov	ebx, [eax + SOCKET.LocalIP]
766
	mov	eax, [eax + SOCKET.RemoteIP]
1196 hidnplayr 767
	call	ICMP_create_packet
1159 hidnplayr 768
 
769
	mov	[esp+32], eax
770
	ret
771
 
772
  .tcp:
773
 
774
	ret
775
 
776
 
777
 
778
 
1206 hidnplayr 779
;-----------------------------------------------
780
;
781
; SOCKET_find_free_port (local port)
782
;
783
; works with INET byte order
784
;
785
;  IN:  type in ecx (TCP/UDP)
786
;  OUT: bx = 0 on error, portnumber otherwise
787
;
788
;-----------------------------------------------
789
align 4
790
socket_find_port:
1159 hidnplayr 791
 
1208 hidnplayr 792
	DEBUGF	1,"Socket_find_free_port\n"
1159 hidnplayr 793
 
1206 hidnplayr 794
	cmp	ecx, IP_PROTO_UDP
795
	je	.udp
1159 hidnplayr 796
 
1206 hidnplayr 797
	cmp	ecx, IP_PROTO_TCP
798
	je	.tcp
1159 hidnplayr 799
 
1206 hidnplayr 800
  .udp:
801
	mov	bx, [last_UDP_port]
802
	je	.continue
803
 
804
  .tcp:
805
	mov	bx, [last_TCP_port]
806
 
807
 
808
  .continue:
809
	inc	bx
810
 
811
  .check_only:
812
	mov	esi, net_sockets
813
 
814
  .next_socket:
815
	mov	esi, [esi + SOCKET.NextPtr]
816
	or	esi, esi
817
	jz	.port_ok
818
 
819
	cmp	[esi + SOCKET.Type], ecx
820
	jne	.next_socket
821
 
822
	rol	bx, 8
823
	cmp	[esi + SOCKET.LocalPort], bx
824
	rol	bx, 8				; this doesnt change the zero flag, does it ?
825
	jne	.next_socket
826
 
827
	cmp	bx, MAX_EPHEMERAL_PORT
828
	jle	.continue
829
 
830
	; todo: WRAP!
831
;        mov     [last_UDP_port], MIN_EPHEMERAL_PORT
832
  .exit:
833
	xor	ebx, ebx
834
 
835
  .port_ok:
836
	rol	bx, 8
837
	ret
838
 
839
;-----------------------------------------------
840
;
841
; SOCKET_check_port (local port)
842
;
843
; works with INET byte order
844
;
845
;  IN:  type in ecx (TCP/UDP)
846
;       port to check in bx
847
;  OUT: bx = 0 on error, unchanged otherwise
848
;
849
;-----------------------------------------------
850
align 4
851
socket_check_port:
852
	mov	esi, net_sockets
853
 
854
  .next_socket:
855
	mov	esi, [esi + SOCKET.NextPtr]
856
	or	esi, esi
857
	jz	.port_ok
858
 
859
	cmp	[esi + SOCKET.Type], ecx
860
	jne	.next_socket
861
 
862
	cmp	[esi + SOCKET.LocalPort], bx
863
	jne	.next_socket
864
 
865
	xor	ebx, ebx
866
 
867
  .port_ok:
868
	ret
869
 
870
 
871
 
872
;-----------------------------------------------
873
;
874
; SOCKET_internal_receiver
875
;
876
; Checks if any socket wants the received data
877
; If so, update the socket
878
;
879
;  IN:  eax = socket number
880
;       ecx = number of bytes
881
;       esi = pointer to beginning of data
882
;       dx = Remote port (in INET byte order)
883
;       edi = IP address of sender
884
;
885
;  OUT: xxx
886
;
887
;-----------------------------------------------
888
align 4
889
socket_internal_receiver:
890
 
891
	DEBUGF 1,"internal socket receiver\n"
892
 
893
	lea	ebx, [eax + SOCKET.lock]
894
	call	wait_mutex
895
 
896
	mov	[eax + SOCKET.RemotePort], dx		; update remote port number
897
	mov	[eax + SOCKET.RemoteIP], edi
898
 
899
	mov	edx, [eax + SOCKET.rxDataCount] 	; get # of bytes already in buffer
900
	DEBUGF 1,"bytes already in socket: %u ", edx
901
 
902
	lea	edi, [ecx + edx]			; check for buffer overflow
903
	cmp	edi, SOCKETBUFFSIZE - SOCKETHEADERSIZE	;
904
	jg	.dump					;
905
 
906
	lea	edi, [eax + SOCKET.rxData + edx]
907
	add	[eax + SOCKET.rxDataCount], ecx 	; increment the count of bytes in buffer
908
	DEBUGF 1,"adding %u bytes\n", ecx
909
 
910
	; copy the data across
911
	push	cx
912
	shr	ecx, 2
913
	rep	movsd
914
	pop	cx
915
	and	cx, 3
916
	rep	movsb
917
 
918
	DEBUGF 1,"socket updated\n"
919
 
920
	mov	[eax + SOCKET.lock], 0
921
 
922
	; flag an event to the application
923
	mov	edx, [eax + SOCKET.PID] 		; get socket owner PID
924
	mov	ecx, 1
925
	mov	esi, TASK_DATA + TASKDATA.pid
926
 
927
       .next_pid:
928
	cmp	[esi], edx
929
	je	.found_pid
930
	inc	ecx
931
	add	esi, 0x20
932
	cmp	ecx, [TASK_COUNT]
933
	jbe	.next_pid
934
	ret
935
 
936
       .found_pid:
937
	shl	ecx, 8
938
	or	[ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK ; stack event
939
	mov	[check_idle_semaphore], 200
940
	ret
941
 
942
       .dump:
943
	mov	[eax + SOCKET.lock], 0
944
	ret
945
 
946
 
947
 
948
 
949
 
1159 hidnplayr 950
; Allocate memory for socket data and put new socket into the list
951
; Newly created socket is initialized with calling PID and number and
952
; put into beginning of list (which is a fastest way).
953
;
954
; @return socket structure address in EAX
955
;
956
proc net_socket_alloc stdcall uses ebx ecx edx edi
957
	stdcall kernel_alloc, SOCKETBUFFSIZE
958
	DEBUGF	1, "K : net_socket_alloc (0x%x)\n", eax
959
	; check if we can allocate needed amount of memory
960
	or	eax, eax
961
	jz	.exit
962
 
963
	; zero-initialize allocated memory
964
	push	eax
965
	mov	edi, eax
966
	mov	ecx, SOCKETBUFFSIZE / 4
967
;        cld
968
	xor	eax, eax
969
	rep	stosd
970
	pop	eax
971
 
972
	; add socket to the list by changing pointers
973
	mov	ebx, net_sockets
974
	push	[ebx + SOCKET.NextPtr]
975
	mov	[ebx + SOCKET.NextPtr], eax
976
	mov	[eax + SOCKET.PrevPtr], ebx
977
	pop	ebx
978
	mov	[eax + SOCKET.NextPtr], ebx
979
	or	ebx, ebx
980
	jz	@f
981
	mov	[ebx + SOCKET.PrevPtr], eax
982
 
983
    @@: ; set socket owner PID to the one of calling process
984
	mov	ebx, [TASK_BASE]
985
	mov	ebx, [ebx + TASKDATA.pid]
986
	mov	[eax + SOCKET.PID], ebx
987
 
988
	; find first free socket number and use it
989
	;mov     edx, ebx
990
	mov	ebx, net_sockets
991
	xor	ecx, ecx
992
  .next_socket_number:
993
	inc	ecx
994
  .next_socket:
995
	mov	ebx, [ebx + SOCKET.NextPtr]
996
	or	ebx, ebx
997
	jz	.last_socket_number
998
	cmp	[ebx + SOCKET.Number], ecx
999
	jne	.next_socket
1000
	;cmp     [ebx + SOCKET.PID], edx
1001
	;jne     .next_socket
1002
	mov	ebx, net_sockets
1003
	jmp	.next_socket_number
1004
 
1005
  .last_socket_number:
1006
	mov	[eax + SOCKET.Number], ecx
1007
 
1008
  .exit:
1009
	ret
1010
endp
1011
 
1012
; Free socket data memory and pop socket off the list
1013
;
1014
; @param sockAddr is a socket structure address
1015
;
1016
proc net_socket_free stdcall uses ebx ecx edx, sockAddr:DWORD
1017
	mov	eax, [sockAddr]
1018
	DEBUGF	1, "K : net_socket_free (0x%x)\n", eax
1019
	; check if we got something similar to socket structure address
1020
	or	eax, eax
1021
	jz	.error
1022
 
1023
	; make sure sockAddr is one of the socket addresses in the list
1024
	mov	ebx, net_sockets
1025
	;mov     ecx, [TASK_BASE]
1026
	;mov     ecx, [ecx + TASKDATA.pid]
1027
  .next_socket:
1028
	mov	ebx, [ebx + SOCKET.NextPtr]
1029
	or	ebx, ebx
1030
	jz	.error
1031
	cmp	ebx, eax
1032
	jne	.next_socket
1033
	;cmp     [ebx + SOCKET.PID], ecx
1034
	;jne     .next_socket
1035
 
1036
	; okay, we found the correct one
1037
	; remove it from the list first, changing pointers
1038
	mov	ebx, [eax + SOCKET.NextPtr]
1039
	mov	eax, [eax + SOCKET.PrevPtr]
1040
	mov	[eax + SOCKET.NextPtr], ebx
1041
	or	ebx, ebx
1042
	jz	@f
1043
	mov	[ebx + SOCKET.PrevPtr], eax
1044
 
1045
    @@: ; and finally free the memory structure used
1046
	stdcall kernel_free, [sockAddr]
1047
	ret
1048
 
1049
  .error:
1050
	DEBUGF	1, "K :   failed\n"
1051
	ret
1052
endp
1053
 
1054
; Get socket structure address by its number
1055
; Scan through sockets list to find the socket with specified number.
1056
; This proc uses SOCKET.PID indirectly to check if socket is owned by
1057
; calling process.
1058
;
1059
; @param sockNum is a socket number
1060
; @return socket structure address or 0 (not found) in EAX
1061
;
1062
proc net_socket_num_to_addr stdcall uses ebx ecx, sockNum:DWORD
1063
	mov	eax, [sockNum]
1064
	; check if we got something similar to socket number
1065
	or	eax, eax
1066
	jz	.error
1067
 
1068
	; scan through sockets list
1069
	mov	ebx, net_sockets
1070
	;mov     ecx, [TASK_BASE]
1071
	;mov     ecx, [ecx + TASKDATA.pid]
1072
  .next_socket:
1073
	mov	ebx, [ebx + SOCKET.NextPtr]
1074
	or	ebx, ebx
1075
	jz	.error
1076
	cmp	[ebx + SOCKET.Number], eax
1077
	jne	.next_socket
1078
	;cmp     [ebx + SOCKET.PID], ecx
1079
	;jne     .next_socket
1080
 
1081
	; okay, we found the correct one
1082
	mov	eax, ebx
1083
	ret
1084
 
1085
  .error:
1086
	xor	eax, eax
1087
	ret
1088
endp
1089
 
1090
; Get socket number by its structure address
1091
; Scan through sockets list to find the socket with specified address.
1092
; This proc uses SOCKET.PID indirectly to check if socket is owned by
1093
; calling process.
1094
;
1095
; @param sockAddr is a socket structure address
1096
; @return socket number (SOCKET.Number) or 0 (not found) in EAX
1097
;
1098
proc net_socket_addr_to_num stdcall uses ebx ecx, sockAddr:DWORD
1099
	mov	eax, [sockAddr]
1100
	; check if we got something similar to socket structure address
1101
	or	eax, eax
1102
	jz	.error
1103
 
1104
	; scan through sockets list
1105
	mov	ebx, net_sockets
1106
	;mov     ecx, [TASK_BASE]
1107
	;mov     ecx, [ecx + TASKDATA.pid]
1108
  .next_socket:
1109
	mov	ebx, [ebx + SOCKET.NextPtr]
1110
	or	ebx, ebx
1111
	jz	.error
1112
	cmp	ebx, eax
1113
	jne	.next_socket
1114
	;cmp     [ebx + SOCKET.PID], ecx
1115
	;jne     .next_socket
1116
 
1117
	; okay, we found the correct one
1118
	mov	eax, [ebx + SOCKET.Number]
1119
	ret
1120
 
1121
  .error:
1122
	xor	eax, eax
1123
	ret
1124
endp