Subversion Repositories Kolibri OS

Rev

Rev 3545 | Rev 3600 | 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
;;  STACK.INC                                                      ;;
7
;;                                                                 ;;
8
;;  TCP/IP stack for KolibriOS                                     ;;
9
;;                                                                 ;;
10
;;    Written by hidnplayr@kolibrios.org                           ;;
11
;;                                                                 ;;
12
;;     Some parts of code are based on the work of:                ;;
13
;;      Mike Hibbett (menuetos network stack)                      ;;
14
;;      Eugen Brasoveanu (solar os network stack and drivers)      ;;
15
;;      mike.dld (kolibrios socket code)                           ;;
16
;;                                                                 ;;
17
;;     TCP part is based on 4.4BSD                                 ;;
18
;;                                                                 ;;
19
;;          GNU GENERAL PUBLIC LICENSE                             ;;
20
;;             Version 2, June 1991                                ;;
21
;;                                                                 ;;
22
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
23
 
24
$Revision: 3523 $
25
 
26
uglobal
27
        net_10ms        dd ?
28
        net_tmr_count   dw ?
29
endg
30
 
3556 hidnplayr 31
DEBUG_NETWORK_ERROR     = 1
32
DEBUG_NETWORK_VERBOSE   = 0
33
 
3545 hidnplayr 34
MAX_NET_DEVICES         = 16
35
ARP_BLOCK               = 1             ; true or false
36
 
37
MIN_EPHEMERAL_PORT      = 49152
38
MIN_EPHEMERAL_PORT_N    = 0x00C0        ; same in Network byte order (FIXME)
39
MAX_EPHEMERAL_PORT      = 61000
40
MAX_EPHEMERAL_PORT_N    = 0x48EE        ; same in Network byte order (FIXME)
41
 
42
; Ethernet protocol numbers
43
ETHER_ARP               = 0x0608
44
ETHER_IPv4              = 0x0008
45
ETHER_IPv6              = 0xDD86
46
ETHER_PPP_DISCOVERY     = 0x6388
47
ETHER_PPP_SESSION       = 0x6488
48
 
49
; PPP protocol numbers
50
PPP_IPv4                = 0x2100
51
PPP_IPV6                = 0x5780
52
 
53
;Protocol family
54
AF_UNSPEC               = 0
55
AF_LOCAL                = 1
56
AF_INET4                = 2
57
AF_INET6                = 10
58
AF_PPP                  = 777
59
 
60
; Internet protocol numbers
61
IP_PROTO_IP             = 0
62
IP_PROTO_ICMP           = 1
63
IP_PROTO_TCP            = 6
64
IP_PROTO_UDP            = 17
65
 
66
; PPP protocol number
67
PPP_PROTO_ETHERNET      = 666
68
 
69
; Socket types
70
SOCK_STREAM             = 1
71
SOCK_DGRAM              = 2
72
SOCK_RAW                = 3
73
 
74
; Socket options
75
SO_ACCEPTCON            = 1 shl 0
76
SO_BROADCAST            = 1 shl 1
77
SO_DEBUG                = 1 shl 2
78
SO_DONTROUTE            = 1 shl 3
79
SO_KEEPALIVE            = 1 shl 4
80
SO_OOBINLINE            = 1 shl 5
81
SO_REUSEADDR            = 1 shl 6
82
SO_REUSEPORT            = 1 shl 7
83
SO_USELOOPBACK          = 1 shl 8
84
SO_BINDTODEVICE         = 1 shl 9
85
 
86
SO_BLOCK                = 1 shl 10    ; TO BE REMOVED
87
SO_NONBLOCK             = 1 shl 31
88
 
89
; Socket flags for user calls
90
MSG_PEEK                = 0x02
91
MSG_DONTWAIT            = 0x40
92
 
93
; Socket level
94
SOL_SOCKET              = 0
95
 
96
 
97
; Socket States
98
SS_NOFDREF              = 0x0001      ; no file table ref any more
99
SS_ISCONNECTED          = 0x0002      ; socket connected to a peer
100
SS_ISCONNECTING         = 0x0004      ; in process of connecting to peer
101
SS_ISDISCONNECTING      = 0x0008      ; in process of disconnecting
102
SS_CANTSENDMORE         = 0x0010      ; can't send more data to peer
103
SS_CANTRCVMORE          = 0x0020      ; can't receive more data from peer
104
SS_RCVATMARK            = 0x0040      ; at mark on input
105
SS_ISABORTING           = 0x0080      ; aborting fd references - close()
106
SS_RESTARTSYS           = 0x0100      ; restart blocked system calls
107
SS_ISDISCONNECTED       = 0x0800      ; socket disconnected from peer
108
 
109
SS_ASYNC                = 0x0100      ; async i/o notify
110
SS_ISCONFIRMING         = 0x0200      ; deciding to accept connection req
111
SS_MORETOCOME           = 0x0400
112
 
113
SS_BLOCKED              = 0x8000
114
 
115
 
116
SOCKET_MAXDATA          = 4096*32     ; must be 4096*(power of 2) where 'power of 2' is at least 8
117
 
118
; Network driver types
119
NET_TYPE_LOOPBACK       = 0
120
NET_TYPE_ETH            = 1
121
NET_TYPE_SLIP           = 2
122
 
123
MAX_backlog             = 20          ; maximum backlog for stream sockets
124
 
125
; Error Codes
126
ENOBUFS                 = 55
127
ECONNREFUSED            = 61
128
ECONNRESET              = 52
129
ETIMEDOUT               = 60
130
ECONNABORTED            = 53
131
 
132
; Api protocol numbers
133
API_ETH                 = 0
134
API_IPv4                = 1
135
API_ICMP                = 2
136
API_UDP                 = 3
137
API_TCP                 = 4
138
API_ARP                 = 5
139
API_PPPOE               = 6
140
API_IPv6                = 7
141
 
142
HWACC_TCP_IPv4          = 1 shl 0
143
 
144
struct  NET_DEVICE
145
 
146
        type            dd ?    ; Type field
147
        mtu             dd ?    ; Maximal Transmission Unit
148
        name            dd ?    ; Ptr to 0 terminated string
149
 
150
        unload          dd ?    ; Ptrs to driver functions
151
        reset           dd ?    ;
152
        transmit        dd ?    ;
153
 
154
        bytes_tx        dq ?    ; Statistics, updated by the driver
155
        bytes_rx        dq ?    ;
156
        packets_tx      dd ?    ;
157
        packets_rx      dd ?    ;
158
 
159
        state           dd ?    ; link state (0 = no link)
160
        hwacc           dd ?    ; bitmask stating enabled HW accelerations (offload engines)
161
 
162
ends
163
 
164
 
165
; Exactly as it says..
166
macro pseudo_random reg {
167
        add     reg, [esp]
168
        rol     reg, 5
169
        xor     reg, [timer_ticks]
170
;        add     reg, [CPU_FREQ]
171
        imul    reg, 214013
172
        xor     reg, 0xdeadbeef
173
        rol     reg, 9
174
}
175
 
176
; Network to Hardware byte order (dword)
177
macro ntohd reg {
178
 
179
        rol     word reg, 8
180
        rol     dword reg, 16
181
        rol     word reg , 8
182
 
183
}
184
 
185
; Network to Hardware byte order (word)
186
macro ntohw reg {
187
 
188
        rol     word reg, 8
189
 
190
}
191
 
192
 
193
include "queue.inc"
194
 
195
include "loopback.inc"
196
include "ethernet.inc"
197
 
198
include "PPPoE.inc"
199
 
200
include "ARP.inc"
201
include "IPv4.inc"
202
include "IPv6.inc"
203
 
204
include "icmp.inc"
205
include "udp.inc"
206
include "tcp.inc"
207
 
208
include "socket.inc"
209
 
210
 
211
 
212
align 4
213
uglobal
214
 
215
        NET_RUNNING     dd  ?
216
        NET_DEFAULT     dd  ?
217
        NET_DRV_LIST    rd  MAX_NET_DEVICES
218
 
219
endg
220
 
221
 
222
;-----------------------------------------------------------------
223
;
224
; stack_init
225
;
226
;  This function calls all network init procedures
227
;
228
;  IN:  /
229
;  OUT: /
230
;
231
;-----------------------------------------------------------------
232
align 4
233
stack_init:
234
 
235
; Init the network drivers list
236
        xor     eax, eax
237
        mov     edi, NET_RUNNING
238
        mov     ecx, (MAX_NET_DEVICES + 2)
239
        rep     stosd
240
 
241
        PPPoE_init
242
 
243
        IPv4_init
244
;        IPv6_init
245
        ICMP_init
246
 
247
        ARP_init
248
        UDP_init
249
        TCP_init
250
 
251
        SOCKET_init
252
 
253
        mov     [net_tmr_count], 0
254
 
255
        ret
256
 
257
 
258
 
259
; Wakeup every tick.
260
proc stack_handler_has_work?
261
 
262
        mov eax, [timer_ticks]
263
        cmp eax, [net_10ms]
264
 
265
        ret
266
endp
267
 
268
 
269
;-----------------------------------------------------------------
270
;
271
; stack_handler
272
;
273
;  This function is called in kernel loop
274
;
275
;  IN:  /
276
;  OUT: /
277
;
278
;-----------------------------------------------------------------
279
align 4
280
stack_handler:
281
 
282
        ; Test for 10ms tick
283
        mov     eax, [timer_ticks]
284
        cmp     eax, [net_10ms]
285
        je      .exit
286
        mov     [net_10ms], eax
287
 
288
        cmp     [NET_RUNNING], 0
289
        je      .exit
290
 
291
        test    [net_10ms], 0x0f        ; 160ms
292
        jnz     .exit
293
 
294
        TCP_timer_160ms
295
 
296
        test    [net_10ms], 0x3f        ; 640ms
297
        jnz     .exit
298
 
299
        TCP_timer_640ms
300
        ARP_decrease_entry_ttls
301
        IPv4_decrease_fragment_ttls
302
 
303
  .exit:
304
        ret
305
 
306
 
307
 
308
align 4
309
NET_link_changed:
310
 
3556 hidnplayr 311
        DEBUGF  DEBUG_NETWORK_VERBOSE, "NET_link_changed device=0x%x status=0x%x\n", ebx, [ebx + NET_DEVICE.state]
3545 hidnplayr 312
 
313
align 4
314
NET_send_event:
315
 
3556 hidnplayr 316
        DEBUGF  DEBUG_NETWORK_VERBOSE, "NET_send_event\n"
3545 hidnplayr 317
 
318
; Send event to all applications
319
        push    edi ecx
320
        mov     edi, SLOT_BASE
321
        mov     ecx, [TASK_COUNT]
322
  .loop:
323
        add     edi, 256
324
        or      [edi + APPDATA.event_mask], EVENT_NETWORK2
325
        loop    .loop
326
        pop     ecx edi
327
 
328
        ret
329
 
330
 
331
 
332
;-----------------------------------------------------------------
333
;
334
; NET_add_device:
335
;
336
;  This function is called by the network drivers,
337
;  to register each running NIC to the kernel
338
;
339
;  IN:  Pointer to device structure in ebx
340
;  OUT: Device num in eax, -1 on error
341
;
342
;-----------------------------------------------------------------
343
align 4
344
NET_add_device:
345
 
3556 hidnplayr 346
        DEBUGF  DEBUG_NETWORK_VERBOSE, "NET_Add_Device: %x\n", ebx   ;;; TODO: use mutex to lock net device list
3545 hidnplayr 347
 
348
        cmp     [NET_RUNNING], MAX_NET_DEVICES
349
        jae     .error
350
 
351
;----------------------------------
352
; Check if device is already listed
353
        mov     eax, ebx
354
        mov     ecx, MAX_NET_DEVICES    ; We need to check whole list because a device may be removed without re-organizing list
355
        mov     edi, NET_DRV_LIST
356
 
357
        repne   scasd                   ; See if device is already in the list
358
        jz      .error
359
 
360
;----------------------------
361
; Find empty slot in the list
362
        xor     eax, eax
363
        mov     ecx, MAX_NET_DEVICES
364
        mov     edi, NET_DRV_LIST
365
 
366
        repne   scasd
367
        jnz     .error
368
 
369
        sub     edi, 4
370
 
371
;-----------------------------
372
; Add device to the found slot
373
        mov     [edi], ebx              ; add device to list
374
 
375
        mov     eax, edi                ; Calculate device number in eax
376
        sub     eax, NET_DRV_LIST
377
        shr     eax, 2
378
 
379
        inc     [NET_RUNNING]           ; Indicate that one more network device is up and running
380
 
381
        cmp     eax, 1                  ; If it's the first network device, try to set it as default
382
        jne     @f
383
        push    eax
384
        call    NET_set_default
385
        pop     eax
386
       @@:
387
 
388
        call    NET_send_event
389
 
3556 hidnplayr 390
        DEBUGF  DEBUG_NETWORK_VERBOSE, "Device number: %u\n", eax
3545 hidnplayr 391
        ret
392
 
393
  .error:
394
        or      eax, -1
3556 hidnplayr 395
        DEBUGF  DEBUG_NETWORK_ERROR, "Adding network device failed\n"
3545 hidnplayr 396
        ret
397
 
398
 
399
 
400
;-----------------------------------------------------------------
401
;
402
; NET_set_default
403
;
404
;  API to set the default interface
405
;
406
;  IN:  Device num in eax
407
;  OUT: Device num in eax, -1 on error
408
;
409
;-----------------------------------------------------------------
410
align 4
411
NET_set_default:
412
 
3556 hidnplayr 413
        DEBUGF  DEBUG_NETWORK_VERBOSE, "NET_set_default: device=%x\n", eax
3545 hidnplayr 414
 
415
        cmp     eax, MAX_NET_DEVICES
416
        jae     .error
417
 
418
        cmp     [NET_DRV_LIST+eax*4], 0
419
        je      .error
420
 
421
        mov     [NET_DEFAULT], eax
422
 
3556 hidnplayr 423
        DEBUGF  DEBUG_NETWORK_VERBOSE, "NET_set_default: succes\n"
3545 hidnplayr 424
        ret
425
 
426
  .error:
427
        or      eax, -1
3556 hidnplayr 428
        DEBUGF  DEBUG_NETWORK_ERROR, "NET_set_default: failed\n"
3545 hidnplayr 429
        ret
430
 
431
 
432
;-----------------------------------------------------------------
433
;
434
; NET_Remove_Device:
435
;
436
;  This function is called by etwork drivers,
437
;  to unregister network devices from the kernel
438
;
439
;  IN:  Pointer to device structure in ebx
440
;  OUT: eax: -1 on error
441
;
442
;-----------------------------------------------------------------
443
align 4
444
NET_remove_device:
445
 
446
        cmp     [NET_RUNNING], 0
447
        je      .error
448
 
449
        cmp     [NET_DRV_LIST], ebx
450
        jne     @f
451
        mov     [NET_DRV_LIST], 0
452
        cmp     [NET_RUNNING], 1
453
        je      @f
454
        ; there are still active devices, find one and make it default
455
        xor     eax, eax
456
        mov     ecx, MAX_NET_DEVICES
457
        mov     edi, NET_DRV_LIST
458
        repe    scasd
459
        je      @f
460
        shr     edi, 2
461
        dec     edi
462
        mov     [NET_DEFAULT], edi
463
       @@:
464
 
465
;----------------------------
466
; Find the driver in the list
467
 
468
        mov     eax, ebx
469
        mov     ecx, MAX_NET_DEVICES
470
        mov     edi, NET_DRV_LIST+4
471
 
472
        repne   scasd
473
        jnz     .error
474
 
475
;------------------------
476
; Remove it from the list
477
 
478
        xor     eax, eax
479
        mov     dword [edi-4], eax
480
 
481
        call    NET_send_event
482
 
483
        dec     [NET_RUNNING]
484
        ret
485
 
486
  .error:
487
        or      eax, -1
488
        ret
489
 
490
 
491
 
492
;-----------------------------------------------------------------
493
;
494
; NET_ptr_to_num
495
;
496
; IN:  ebx = ptr to device struct
497
; OUT: edi = -1 on error, device number otherwise
498
;
499
;-----------------------------------------------------------------
500
align 4
501
NET_ptr_to_num:
502
        push    ecx
503
 
504
        mov     ecx, MAX_NET_DEVICES
505
        mov     edi, NET_DRV_LIST
506
 
507
  .loop:
508
        cmp     ebx, [edi]
509
        jz      .found
510
        add     edi, 4
511
        dec     ecx
512
        jnz     .loop
513
 
514
        ; repnz  scasd could work too if eax is used instead of ebx!
515
 
516
        or      edi, -1
517
 
518
        pop     ecx
519
        ret
520
 
521
  .found:
522
        sub     edi, NET_DRV_LIST
523
        shr     edi, 2
524
 
525
        pop     ecx
526
        ret
527
 
528
;-----------------------------------------------------------------
529
;
530
; checksum_1
531
;
532
;  This is the first of two functions needed to calculate a checksum.
533
;
534
;  IN:  edx = start offset for semi-checksum
535
;       esi = pointer to data
536
;       ecx = data size
537
;  OUT: edx = semi-checksum
538
;
539
;
540
; Code was optimized by diamond
541
;
542
;-----------------------------------------------------------------
543
align 4
544
checksum_1:
545
 
546
        shr     ecx, 1
547
        pushf
548
        jz      .no_2
549
 
550
        shr     ecx, 1
551
        pushf
552
        jz      .no_4
553
 
554
        shr     ecx, 1
555
        pushf
556
        jz      .no_8
557
 
558
  .loop:
559
        add     dl, [esi+1]
560
        adc     dh, [esi+0]
561
 
562
        adc     dl, [esi+3]
563
        adc     dh, [esi+2]
564
 
565
        adc     dl, [esi+5]
566
        adc     dh, [esi+4]
567
 
568
        adc     dl, [esi+7]
569
        adc     dh, [esi+6]
570
 
571
        adc     edx, 0
572
        add     esi, 8
573
 
574
        dec     ecx
575
        jnz     .loop
576
 
577
        adc     edx, 0
578
 
579
  .no_8:
580
        popf
581
        jnc     .no_4
582
 
583
        add     dl, [esi+1]
584
        adc     dh, [esi+0]
585
 
586
        adc     dl, [esi+3]
587
        adc     dh, [esi+2]
588
 
589
        adc     edx, 0
590
        add     esi, 4
591
 
592
  .no_4:
593
        popf
594
        jnc     .no_2
595
 
596
        add     dl, [esi+1]
597
        adc     dh, [esi+0]
598
 
599
        adc     edx, 0
600
        inc     esi
601
        inc     esi
602
 
603
  .no_2:
604
        popf
605
        jnc     .end
606
 
607
        add     dh, [esi+0]
608
        adc     edx, 0
609
  .end:
610
        ret
611
 
612
;-----------------------------------------------------------------
613
;
614
; checksum_2
615
;
616
;  This function calculates the final ip/tcp/udp checksum for you
617
;
618
;  IN:  edx = semi-checksum
619
;  OUT: dx = checksum (in INET byte order)
620
;
621
;-----------------------------------------------------------------
622
align 4
623
checksum_2:
624
 
625
        mov     ecx, edx
626
        shr     ecx, 16
627
        and     edx, 0xffff
628
        add     edx, ecx
629
 
630
        mov     ecx, edx
631
        shr     ecx, 16
632
        add     dx, cx
633
        test    dx, dx          ; it seems that ZF is not set when CF is set :(
634
        not     dx
635
        jnz     .not_zero
636
        dec     dx
637
  .not_zero:
638
        xchg    dl, dh
639
 
3556 hidnplayr 640
        DEBUGF  DEBUG_NETWORK_VERBOSE, "Checksum: %x\n", dx
3545 hidnplayr 641
 
642
        ret
643
 
644
 
645
 
646
;----------------------------------------------------------------
647
;
648
;  System function to work with network devices (75)
649
;
650
;----------------------------------------------------------------
651
align 4
652
sys_network:                    ; FIXME: make default device easily accessible
653
 
654
        cmp     ebx, -1
655
        jne     @f
656
 
657
        mov     eax, [NET_RUNNING]
658
        jmp     .return
659
 
660
   @@:
661
        cmp     bh, MAX_NET_DEVICES             ; Check if device number exists
662
        jae     .doesnt_exist
663
 
664
        mov     esi, ebx
665
        and     esi, 0x0000ff00
666
        shr     esi, 6
667
 
668
        cmp     dword [esi + NET_DRV_LIST], 0   ; check if driver is running
669
        je      .doesnt_exist
670
 
671
        mov     eax, [esi + NET_DRV_LIST]
672
 
673
        and     ebx, 0x000000ff
674
        cmp     ebx, .number
675
        ja      .doesnt_exist
676
        jmp     dword [.table + 4*ebx]
677
 
678
  .table:
679
        dd      .get_type               ; 0
680
        dd      .get_dev_name           ; 1
681
        dd      .reset                  ; 2
682
        dd      .stop                   ; 3
683
        dd      .get_ptr                ; 4
684
        dd      .get_drv_name           ; 5
685
        dd      .set_default            ; 6
686
  .number = ($ - .table) / 4 - 1
687
 
688
  .get_type:                            ; 0 = Get device type (ethernet/token ring/...)
689
 
690
        mov     eax, [eax + NET_DEVICE.type]
691
        jmp     .return
692
 
693
 
694
  .get_dev_name:                        ; 1 = Get device name
695
 
696
        mov     esi, [eax + NET_DEVICE.name]
697
        mov     edi, ecx
698
 
699
        mov     ecx, 64/4 ; max length
700
        rep     movsd
701
 
702
        xor     eax, eax
703
        jmp     .return
704
 
705
  .reset:                               ; 2 = Reset the device
706
 
707
        call    [eax + NET_DEVICE.reset]
708
        jmp     .return
709
 
710
  .stop:                                ; 3 = Stop driver for this device
711
 
712
        call    [eax + NET_DEVICE.unload]
713
        jmp     .return
714
 
715
 
716
  .get_ptr:                             ; 4 = Get driver pointer
717
 
718
        jmp     .return
719
 
720
 
721
  .get_drv_name:                        ; 5 = Get driver name
722
 
723
        xor     eax, eax
724
        jmp     .return
725
 
726
 
727
  .set_default:                         ; 6 = Set default device
728
 
729
        call    NET_set_default
730
        jmp     .return
731
 
732
  .doesnt_exist:
733
        mov     eax, -1
734
 
735
  .return:
736
        mov     [esp+32], eax
737
        ret
738
 
739
 
740
;----------------------------------------------------------------
741
;
742
;  System function to work with protocols  (76)
743
;
744
;----------------------------------------------------------------
745
align 4
746
sys_protocols:
747
        cmp     bh, MAX_NET_DEVICES             ; Check if device number exists
748
        jae     .doesnt_exist
749
 
750
        mov     esi, ebx
751
        and     esi, 0x0000ff00
752
        shr     esi, 6                          ; now we have the device num * 4 in esi
753
        cmp     [esi + NET_DRV_LIST], 0         ; check if driver is running
754
        je      .doesnt_exist
755
 
756
        push    .return                         ; return address (we will be using jumps instead of calls)
757
 
758
        mov     eax, ebx                        ; set ax to protocol number
759
        shr     eax, 16                         ;
760
 
761
        cmp     ax, API_ETH
762
        je      ETH_api
763
 
764
        cmp     ax, API_IPv4
765
        je      IPv4_api
766
 
767
        cmp     ax, API_ICMP
768
        je      ICMP_api
769
 
770
        cmp     ax, API_UDP
771
        je      UDP_api
772
 
773
        cmp     ax, API_TCP
774
        je      TCP_api
775
 
776
        cmp     ax, API_ARP
777
        je      ARP_api
778
 
779
        cmp     ax, API_PPPOE
780
        je      PPPoE_api
781
 
782
        cmp     ax, API_IPv6
783
        je      IPv6_api
784
 
785
        add     esp, 4                           ; if we reached here, no function was called, so we need to balance stack
786
 
787
  .doesnt_exist:
788
        mov     eax, -1
789
 
790
  .return:
791
        mov     [esp+28+4], eax                 ; return eax value to the program
792
        ret