Sourcecode Fortschritt


  • Mod

    Bitte darauf achten, dass bei den cross-tools die enthaltenen binutils, darunter auch ld.exe nicht mehr zu einem lauffähigen produkt führen (#PF).

    MrX wird demnächst ein neues bundle für die crosstools hochladen. ⚠

    http://kloke-witten.dyndns.org/~philipp/bin.zip <--- wenn es eilt



  • Version 0.0.2.102:

    - Parameterübergabe wieder über eax/ecx
    - Fehlerbehandlung im Floppytreiber verbessert
    - Konsolen überarbeitet (Stabilität, Code vereinfacht)


  • Mod

    version = "0.0.2.103 - Rev: 942"

    TCP weiter ausgebaut:
    - Senden klappt
    - Checksum (UDP, TCP) bewirkt #PF
    - 3-way-handshake: SYN kann bereits mit SYN ACK beantwortet werden


  • Mod

    version = "0.0.2.105 - Rev: 944" (beim nächsten Mal bitte stehen lassen, wurde offenbar eine übersprungen)

    checksum für UDP: 0 (wegen DHCP)
    checksum für TCP: aktiviert, wireshark validiert diese aber als "incorrect" ⚠

    Checksum: 0x7754 [incorrect, should be 0xba47 (maybe caused by "TCP checksum offload"?)]
    

  • Mod

    version = "0.0.2.105 - Rev: 944"

    Parameter "protocol" ergänzt:
    uint16_t udptcpCalculateChecksum(void* p, size_t length, uint8_t sourceIp[4], uint8_t destinationIp[4], uint16_t protocol)

    Checksum falsch.


  • Mod

    version = "0.0.2.106 - Rev: 945"

    - TCP-Checksum noch nicht korrekt
    - internetChecksum (Fkt. wird bereits bei ip und icmp eingesetzt) mit verwendet


  • Mod

    version = "0.0.2.107 - Rev: 946"

    - tcp checksum noch nicht korrekt, aber schon nahe dran ^^


  • Mod

    version = "0.0.2.108 - Rev: 947"

    - tcp checksum noch falsch
    - pseudoheader byteweise aufgebaut für besseren Überblick

    uint16_t udptcpCalculateChecksum(void* p, uint16_t length, uint8_t srcIP[4], uint8_t destIP[4], uint16_t protocol)
    {
        uint32_t pseudoHeaderChecksum = 0;
        uint8_t  header[12]; // Pseudo header
        uint8_t* data = header;
        uint8_t  count = 12; // pseudo header contains 12 byte
    
        for (uint8_t i=0; i<4; i++)
        {
            header[i] = srcIP[i];
        }
        for (uint8_t i=4; i<8; i++)
        {
            header[i] = destIP[i-4];
        }
    
        header[8]  = 0;
        header[9]  = protocol;
        header[10] = length & 0xFF;
        header[11] = (length >> 8) & 0xFF;
    
        while (count > 1)
        {
            // pseudo header contains 6 WORD
            pseudoHeaderChecksum += (data[0] << 8) | data[1]; // Big Endian
            data   += 2;
            count  -= 2;
        }
    
        return internetChecksum(p, length, pseudoHeaderChecksum); // util.c
    }
    
    // compute internet checksum for "count" bytes beginning at location "addr"
    uint16_t internetChecksum(void* addr, size_t count, uint32_t pseudoHeaderChecksum)
    {
        uint32_t sum  = pseudoHeaderChecksum;
        uint8_t* data = addr;
    
        while (count > 1) // inner loop
        {
            sum   += (data[0] << 8) | data[1]; // Big Endian
            data  += 2;
            count -= 2;
        }
    
        if (count > 0) // add left-over byte, if any
        {
            sum += data[0] << 8;
        }
    
        while (sum >> 16) // fold 32-bit sum to 16 bits
        {
            sum = (sum & 0xFFFF) + (sum >> 16);
        }
    
        return ~sum & 0xFFFF;
    }
    
    void tcpSend(network_adapter_t* adapter, void* data, uint32_t length, uint16_t srcPort, uint8_t srcIP[4], uint16_t destPort, uint8_t destIP[4], tcpFlags flags, uint32_t seqNumber, uint32_t ackNumber)
    {
    //...
        packet->checksum = 0; // for checksum calculation
        packet->checksum = htons(udptcpCalculateChecksum((void*)packet, length + sizeof(tcpPacket_t), srcIP, destIP, 6));
    
        ipv4_send(adapter, packet, length + sizeof(tcpPacket_t), destIP, 6);
    //...
    }
    

    Wenn man header[8] ... [11] dreht, wird die differenz kleiner.

    Hier ein Hexpaket:

    0013d41127a50010a70f0a0c0800450000280000400080067707c0a80161c0a8011700170607000000001cb30fc95012fffff3750000000000000000
    Checksum: 0xf375 [incorrect, should be 0xf96f (maybe caused by "TCP checksum offload"?)]

    Hex-Code:
    IP-Paket: 450000280000400080067707c0a80161c0a80117
    TCP-Paket: 00170607000000001cb30fc95012fffff3750000

    Internet Protocol Version 4, Src: 192.168.1.97 (192.168.1.97), Dst: 192.168.1.23 (192.168.1.23)

    Transmission Control Protocol, Src Port: telnet (23), Dst Port: simba-cs (1543), Seq: 0, Ack: 1, Len: 0
    (Len ist hier die Datenlänge)

    chat:
    <ehenkes>TCP-Paket: 00170607000000001cb30fc95012fffff3750000
    <ehenkes>Src: 192.168.1.97 (192.168.1.97), Dst: 192.168.1.23 (192.168.1.23)
    <ehenkes>raus kommen muss: 0xf96f
    <ehenkes>daten gibts keine, reiner header
    <ehenkes>udptcpCalculateChecksum(void* p, uint16_t length, uint8_t srcIP[4], uint8_t destIP[4], uint16_t protocol)
    <ehenkes>p zeigt auf den tcp-header
    <ehenkes>length = sizeof(tcp_header)
    <ehenkes>IPs sind klar
    <ehenkes>MrX: gut so?
    <MrX>ja
    <ehenkes>Header length: 20 bytes
    <ehenkes>des TCP headers
    

    Weitere Pakete: (IPs gleich)

    <ehenkes>0017062800000000c56a32495012ffff007827a5    Checksum: 0x0078 [incorrect, should be 0x0672 (maybe caused by "TCP checksum offload"?)]
    
    <ehenkes>0017062900000000591dc44a5012fffffc630604  Checksum: 0xfc63 [incorrect, should be 0x025e (maybe caused by "TCP checksum offload"?)]
    

    erzeugt mit:

    header[11]  = 0;
        header[10]  = protocol;
        header[9]   = length & 0xFF;
        header[8]   = (length >> 8) & 0xFF;
    

    Nach Simulation:
    <MrX>Übrigens weiß ich, wie Du deine Variante lauffähig kriegst.

    header[8]  = 0;
    header[9]  = protocol;
    header[11] = length & 0xFF;
    header[10] = (length >> 8) & 0xFF;
    

  • Mod

    version = "0.0.2.109 - Rev: 948"

    MEILENSTEIN: http://www.c-plusplus.net/forum/p2078201#2078201
    Erfolg! (thx to Mrx for simulating TCP checksum) 🙂 👍

    tcp.h:

    typedef struct 
    {
            uint8_t src[4];
            uint8_t dest[4];
            uint8_t res;
            uint8_t prot;
            uint16_t length;
    } __attribute__((packed)) tcpPseudoHeader_t;
    

    network.c:

    uint16_t udptcpCalculateChecksum(void* p, uint16_t length, uint8_t srcIP[4], uint8_t destIP[4], uint16_t protocol)
    {
        tcpPseudoHeader_t pseudo;
        for (uint8_t i=0; i<4; i++)
        {
            pseudo.src[i] = srcIP[i];
            pseudo.dest[i] = destIP[i];
        }
        pseudo.length = htons(length);
        pseudo.prot = protocol;
        pseudo.res = 0;
    
        uint32_t pseudoHeaderChecksum = 0;
        uint8_t  count = 12; // pseudo header contains 12 byte
    
        uint8_t* data = (uint8_t*)&pseudo;   
    
        while (count > 1)
        {
            // pseudo header contains 6 WORD
            pseudoHeaderChecksum += (data[0] << 8) | data[1]; // Big Endian
            data   += 2;
            count  -= 2;
        }
    
        return internetChecksum(p, length, pseudoHeaderChecksum); // util.c
    }
    

    ... und schon geht der Weg zum ESTABLISHED:

    12 14.042894 192.168.1.23 192.168.1.97 TCP 62 shockwave > telnet [SYN] Seq=0 Win=65535 Len=0 MSS=1460 SACK_PERM=1
    13 14.052667 192.168.1.97 192.168.1.23 TCP 60 telnet > shockwave [SYN, ACK] Seq=0 Ack=1 Win=65535 Len=0
    14 14.052691 192.168.1.23 192.168.1.97 TCP 54 shockwave > telnet [ACK] Seq=1 Ack=1 Win=65535 Len=0

    ➡ syn - syn ack - ack (TCP 3-way-handshake) 👍

    Mit dieser Version kann man erste versuche bei TCP/IP unternehmen, z.B. TELNET nutzen: http://www.henkessoft.de/OS_Dev/Bilder/rev.948_TCP_TELNET.PNG

    http://www.manpagez.com/man/1/telnet/ <--- Kommandos


  • Mod

    rev. 949:

    TCP weiter ausgebaut, vor allem werden nun die Transition States angezeigt:
    (CLOSED -->) LISTEN --> SYN_RECEIVED --> ESTABLISHED

    Length: 66 Rcv: 00-10-A7-0F-0A-0C  Transm.: 00-13-D4-11-27-A5                   
    Ethernet 2. Prot. type: IP.  IP version: 4, IP Header Length: 20 byte           
    TCP: src port: 1232  dest port: 23 URG: 0 ACK: 0 PSH: 0 RST: 0 SYN: 1 FIN: 0    
    TCP prev. state: CLOSED                                                         
    TCP set from CLOSED to LISTEN.                                                  
    TCP curr. state: LISTEN                                                         
    
    Length: 66 Rcv: 00-10-A7-0F-0A-0C  Transm.: 00-13-D4-11-27-A5                   
    Ethernet 2. Prot. type: IP.  IP version: 4, IP Header Length: 20 byte           
    TCP: src port: 1232  dest port: 23 URG: 0 ACK: 0 PSH: 0 RST: 0 SYN: 1 FIN: 0    
    TCP prev. state: LISTEN                                                         
    
    EthernetSend: length: 54.                                                       
    
    >>> Transmission starts <<<                                                     
    Physical Address of Tx Buffer = 014051D8h                                       
    packet sent.                                                                    
    TCP curr. state: SYN_RECEIVED                                                   
    
    Length: 64 Rcv: 00-10-A7-0F-0A-0C  Transm.: 00-13-D4-11-27-A5                   
    Ethernet 2. Prot. type: IP.  IP version: 4, IP Header Length: 20 byte           
    TCP: src port: 1232  dest port: 23 URG: 0 ACK: 1 PSH: 0 RST: 0 SYN: 0 FIN: 0    
    TCP prev. state: SYN_RECEIVED                                                   
    TCP curr. state: ESTABLISHED
    

    Da wir mit CLOSED starten und noch keine sockets bauen, müssen wir den Übergang zu LISTEN noch etwas künstlich durchführen:

    void tcpListen(network_adapter_t* adapter)
    {
        adapter->TCP_PrevState = adapter->TCP_CurrState;
        adapter->TCP_CurrState = LISTEN;
    
        // TODO: more action needed?
    }
    
    Erst ab dort geht es geregelt weiter:
    
    [cpp]if (tcp->SYN && !tcp->ACK) // SYN
        {
            adapter->TCP_PrevState = adapter->TCP_CurrState;
            if (adapter->TCP_CurrState == CLOSED)
            {   
                printf("TCP set from CLOSED to LISTEN.\n");
                tcpListen(adapter);
            }
            else if (adapter->TCP_CurrState == LISTEN)
            {
                tcpSend(adapter, 0, 0, htons(tcp->destPort), adapter->IP_address, htons(tcp->sourcePort), transmittingIP, SYN_ACK_FLAG, 0 /*seqNumber*/ , tcp->sequenceNumber+htonl(1) /*ackNumber*/);
                adapter->TCP_CurrState = SYN_RECEIVED;
            }
    //...
    

    telnet baut zumindest einen "Kontakt" zu uns auf, erwartet aber wohl mehr von seinem "Server" als nur einen 3-way-handshake:

    Microsoft Telnet> open 192.168.1.97
    Verbindungsaufbau zu 192.168.1.97...
    

  • Mod

    version = "0.0.2.111 - Rev: 950"

    TCP/Telnet-Datenübertragung, allerdings noch ohne aktive Bestätigung seitens PrettyOS:
    http://www.henkessoft.de/OS_Dev/Bilder/rev.950_TCP_TELNET_DATEN.PNG

    Mit strg+c kann man für Experimente den Zustand LISTEN erneut setzen.

    TODO: Im state "ESTABLISHED" den Empfang von Daten mit der korrekten ACK bestätigen, damit der "Retransmission Timer" des Senders keine erneute Versendung dieses Paktes veranlasst (s. Bild oben).

    Hier ist eine gute Literaturstelle für den Datenaustausch-Mechanismus: http://www.rhyshaden.com/tcp.htm


  • Mod

    version = "0.0.2.112 - Rev: 951"
    Experimentelle Version: Man muss genau 10 Byte senden, damit es genau klappt.
    TODO: Länge des TCP-Datenpakets bestimmen und übergeben.

    Foto: http://www.henkessoft.de/OS_Dev/Bilder/rev.951_TCP_TELNET_DATENAUSTAUSCH.PNG

    if (!tcp->SYN && !tcp->FIN && tcp->ACK) // ACK
        {
            adapter->TCP_PrevState = adapter->TCP_CurrState;    
    
            if (adapter->TCP_CurrState == ESTABLISHED) // ESTABLISHED --> DATA TRANSFER
            {
                uint32_t length_of_tcpData = 10; // TODO: find length of data !
                printf("\ntcp packet data:");
                for (uint16_t i=0; i<length_of_tcpData; i++)
                {
                    printf("%c", *(((uint8_t*)(tcp+1))+i) );
                }
                tcpSend(adapter, 0, 0, htons(tcp->destPort), adapter->IP_address, htons(tcp->sourcePort), transmittingIP, ACK_FLAG, tcp->acknowledgmentNumber /*seqNumber*/, tcp->sequenceNumber+htonl(length_of_tcpData) /*ackNumber*/);
            }
    

    ACK bei Datenempfang klappt nun auch (Berechnung von Seq.- und Ack.-Nummer).

    Tippt man bei telnet "close" ein, kommt auch ein ACK. Mit strg+c kann man dann wieder bei LISTEN starten. Alles noch etwas "getrickst". Aber die ACK-Technik kann man sehr schön testen, und vor allem klappt es. 🙂



  • Version 0.0.2.113:

    - Kernel Stack von 0x190000 nach 0x1000000 verschoben (Vermeidung einer Kollision mit KERNEL.BIN)
    - Code aufgeräumt


  • Mod

    version = "0.0.2.114 - Rev: 953"

    Nun sind auch variable Längen des TCP-Datenpakets möglich. Wir reichen uns die Paketlänge von unten nach tcpReceive(network_adapter_t* adapter, tcpPacket_t* tcp, uint8_t transmittingIP[4], size_t length) durch.

    Codeausschnitt:

    if (adapter->TCP_CurrState == ESTABLISHED) // ESTABLISHED --> DATA TRANSFER
            {
                uint32_t tcpDataLength = -4 /* frame ? */ + length - (tcp->dataOffset << 2);
                printf("\ntcp packet data:");
                for (uint16_t i=0; i<tcpDataLength; i++)
                {
                    printf("%c", *(((uint8_t*)(tcp+1))+i) );
                }
                tcpSend(adapter, 0, 0, htons(tcp->destPort), adapter->IP_address, htons(tcp->sourcePort), transmittingIP, ACK_FLAG, tcp->acknowledgmentNumber /*seqNumber*/, tcp->sequenceNumber+htonl(tcpDataLength) /*ackNumber*/);
            }
    

    telnet:

    open 192.168.1.97
    sen ...
    sen ................
    sen .......
    close
    

    anschließend bei PrettyOS wieder strg+c und erneut connection aufbauen, oder auch direkt open ... .

    Kann alles in wireshark und bei PrettyOS verfolgt werden. 🙂


  • Mod

    version = "0.0.2.115 - Rev: 954"

    tcp.h weiter mit structs (DRAFT) gefüllt, um mit connections und dazu gehörigen sockets arbeiten zu können:

    typedef struct
    {
        uint32_t SND_UNA;   // Send Unacknowledged
        uint32_t SND_NXT;   // Send Next
        uint16_t SND_WND;   // Send Window
        uint32_t SND_ISS;   // Initial send sequence number
        uint32_t RCV_NXT;   // Sequence number of next received set
        uint16_t RCV_WND;   // Receive Window
        uint32_t RCV_IRS;   // Initial receive sequence number
    } __attribute__((packed)) tcpTransmissionControlBlock_t;
    
    typedef struct
    {
        uint16_t port;
        uint8_t  IP[4];
        network_adapter_t* adapter;
    } __attribute__((packed)) tcpSocket_t;
    
    typedef struct
    {
        tcpSocket_t localSocket;
        tcpSocket_t remoteSocket;
        tcpTransmissionControlBlock_t tcb;
        TCP_state TCP_PrevState;
        TCP_state TCP_CurrState;
    } __attribute__((packed)) tcpConnection_t;
    
    typedef struct
    {
        uint32_t SEG_SEQ; // Sequence number
        uint32_t SEG_ACK; // Acknoledgement number
        uint32_t SEG_LEN; // segment length
        uint32_t SEG_WND; // segment windows
        tcpFlags SEG_CTL; // control bits
    }  __attribute__((packed)) tcpSegment_t;
    

  • Mod

    version = "0.0.2.116 - Rev: 955"

    TCP weiter ausgebaut. Die TCP States zu tcpConn umgehängt.

    In network.c das TCP Server "passive open" eingerichtet:

    // open TCP Server with State "LISTEN"
        adapter->tcpConn = malloc(sizeof(tcpConnection_t), 0, "tcp connection");
        adapter->tcpConn->localSocket.port = getFreeSocket();
        memcpy(adapter->tcpConn->localSocket.IP, adapter->IP_address, 4);
        adapter->tcpConn->TCP_PrevState = CLOSED;
        adapter->tcpConn->TCP_CurrState = LISTEN;
        // TODO: ...
    

    networktypes.h fehlt im Commit ⚠


  • Mod



  • Version 0.0.2.118:

    - Ausgabe verbessert
    - Mutexes verbessert
    - PCI nutzt nun eine Liste statt eines statischen Arrays
    - Aufgeräumt



  • Version 0.0.2.119:

    - TCP überarbeitet. (BUG: Datentransfer funktioniert nicht.)


  • Mod

    version = "0.0.2.120 - Rev: 959"

    Aktives öffnen und TCP ("SYN") senden (mit strg+w) klappt.
    Problem: Internet Checksum ist falsch! (Ursache bisher unklar, da das Senden von SYN ACK oder FIN ACK als server bisher klappt)

    Ablauf:

    1. PrettyOS bootet, holt sich per DHCP seine IP
    2. Man pingt PrettyOS von 192.168.1.23 an, damit der rechner in die ARP-Tabelle eingetragen wird (diese IP steht konkret in strg+w in keyboard.c drinnen, also ändern auf eigenen rechner)
    3. Man gibt strg+w ein bei PrettyOS um aktiv ein SYN zu senden
      Fazit: SYN senden klappt, aber checksum falsch
    TCP-Paket: 0402001700000000000000005002ffff88b00000
    Checksum: 0x88b0 [incorrect, should be 0x2801 ...]
    

    Test mit dem Simulationsprogramm ergibt die korrekte Checksum, also stimmen die Eingangsdaten in die Berechnung für diese nicht.

    PS: der datentransfer in rev. 958 klappt (war offenbar ein TCP-Netzproblem)


Anmelden zum Antworten