Sourcecode Fortschritt
-
version = "0.0.2.95 - Rev: 934"
SIP ersatzlos gestrichen
Problem: Zusammenhang netzwork adapter und IP geht verloren
-
version = "0.0.2.96 - Rev: 935"
Fehler bei ACK auf DHCP_Inform korrigiert. Your IP (dhcp->yiaddr) wird nur übernommen, wenn ungleich 0.0.0.0:
static void useDHCP_IP(network_adapter_t* adapter, dhcp_t* dhcp) { if (dhcp->yiaddr[0] || dhcp->yiaddr[1] || dhcp->yiaddr[2] || dhcp->yiaddr[3]) { for(uint8_t i = 0; i < 4; i++) adapter->IP_address[i] = dhcp->yiaddr[i]; } }
-
version = "0.0.2.97 - Rev: 936"
Endlich habe ich einen Trick gefunden, wie man auch die Antworten des DHCP-Servers in wireshark von einem anderen PC im LAN beobachten kann. Man muss bei den Anfragen die Forderung stellen, dass die Antwort an alle (BROADCAST) gesendet wird.
Beweis-Foto: http://www.henkessoft.de/OS_Dev/Bilder/rev936.PNG
Nachdem dieser Ablauf nun eindeutig demonstriert werden konnte, bitte ich um Reproduktion auch an anderer Stelle.
-
Version 0.0.2.98:
- Unterstützung von Parametern beim Programmstart
- Hello-Userprogramm zeigt übergebene Parameter an
- Verbessertes makefile für other_userprogs
-
Tests von Cuervo mit der vorhergehenden Vesrion:
- DHCP_Release funktioniert. Wenn der DHCP-Server will, wird es als abgelaufen angezeigt
- Wir müssen das Angebot aus OFFER verwenden für REQUEST anstelle der konstanten RIP (das kann der Server anders sehen ^^) aus network.h
- HOST NAME angeben bei den optionsFotos (Cuervo): http://prettyos.fanofblitzbasic.de/PrettyNWPics.zip
MrX: deine Version produziert einen #PF F000EF6F eip: 115391
ckernel.c: shell auskommentiert, "executeFile("1:/ttt.ELF", 0, 0); // TEST" eingefügt, klappt bestens. Bitte in Ordnung bringen.
-
version = "0.0.2.99 - Rev: 938"
shell auskommentiert, ttt wird testweise ausgeführt.
Netzwerk: Hostname "PrettyOS" eingeführt bei DHCP, DHCP_Request übernimmt IP aus DHCP_Offer.
-
Version 0.0.2.100:
- cpu.c: Es wird überprüft, ob cpuid unterstützt wird; Funktionen zum Lesen und Schreiben des MSR implementiert
- memory.txt geupdated und erweitert
- Bugfix/Hack: Shell nimmt nun argv/argc-Parameter beim Start
- Projektmappen: Verbesserte Intellisense-Kompatibilität durch Dummy-Header VCcompatibility.h und verbesserte Includepfad-Einstellungen
-
Version 0.0.2.101:
- Neuer Bugfix-Versuch. argc/argv nun via user stack übergeben.
-
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)
-
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
-
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"?)]
-
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.
-
version = "0.0.2.106 - Rev: 945"
- TCP-Checksum noch nicht korrekt
- internetChecksum (Fkt. wird bereits bei ip und icmp eingesetzt) mit verwendet
-
version = "0.0.2.107 - Rev: 946"
- tcp checksum noch nicht korrekt, aber schon nahe dran ^^
-
version = "0.0.2.108 - Rev: 947"
- tcp checksum noch falsch
- pseudoheader byteweise aufgebaut für besseren Überblickuint16_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: 00170607000000001cb30fc95012fffff3750000Internet 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;
-
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=0syn - 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
-
rev. 949:
TCP weiter ausgebaut, vor allem werden nun die Transition States angezeigt:
(CLOSED -->) LISTEN --> SYN_RECEIVED --> ESTABLISHEDLength: 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...
-
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.PNGMit 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
-
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.