Subversion Repositories Kolibri OS

Rev

Rev 5363 | Rev 5584 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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