u_int32_t Was ist das?



  • Hi,
    Ich bin mir nicht sicher ob das ANSI C ist, wenn nein bitte verschieben.

    Also ich soll einen Kernel so umschreiben das er bei jedem TCP/IP Error den Header des Packetes in ein Logfile schreibt.
    Weiter unten habe ich die Struktur die den Header darstellt gepostet, leider kann ich mit dem u_int16_t nichts anfangen.
    Außerdem ist mir nicht ganz klar wieso in der Struktur nach dem __u16 mehrere Variablen?!? ohne Typendefinition deklariert werden (ergibt sich vllt wenn jem das u_int16_t erklärt).
    Was ich brauche ist wie gesagt eine Erklärung, und evt. Tipps wie ich den Header in ein Char Array bekomme.

    Bin für jede Hilfe dankbar.
    Gruß HiFish

    typedef         __u16           u_int16_t;
    typedef         __u32           u_int32_t;
    
    struct tcphdr {
            __u16   source;
            __u16   dest;
            __u32   seq;
            __u32   ack_seq;
    #if defined(__LITTLE_ENDIAN_BITFIELD)
            __u16   res1:4,
                    doff:4,
                    fin:1,
                    syn:1,
                    rst:1,
                    psh:1,
                    ack:1,
                    urg:1,
                    ece:1,
                    cwr:1;
    #elif defined(__BIG_ENDIAN_BITFIELD)
            __u16   doff:4,
                    res1:4,
                    cwr:1,
                    ece:1,
                    urg:1,
                    ack:1,
                    psh:1,
                    rst:1,
                    syn:1,
                    fin:1;
    #else
    #error  "Adjust your <asm/byteorder.h> defines"
    #endif
            __u16   window;
            __u16   check;
            __u16   urg_ptr;
    };
    


  • kann jetzt mit den typedefs nix anfangen aber das sind halt aliasnamen für die datentypen (16 und 32 bit, also short und int (?))...
    Zum zweiten problem:
    was hälst du davon? 😉

    int a,
    b,
    c;
    

    geht doch auch, da die variablen ja nur von kommata getrennt sind.

    Var:1;
    

    sind übrignes bitfelder, sie kann also nur den wert 0 und 1 annehmen. 8 davon in einer Struktur ergibt eine 1 Byte grosse struct.
    http://www.pronix.de/pronix-776.html



  • das u_int16_t bzw. __u16 ist ein 16-bit vorzeichenloser datentyp, das gleich gilt für u_int32_t bzw. __u32 (vorzeichenlos) allerdings 32-bittig.

    wenn du's in einem char array haben willst: unsigned char tcphdr[20];
    ein tcp header hat mindestens 20 bytes (ohne options).
    guckst du: http://www.faqs.org/rfcs/rfc793.html (unter 3.1 header format).



  • @bill bones: Ups das mit dem Koma haette ich auch selber sehen können.
    @ten:Hab mir den link mal durchgelesen nun weiß ich wenigstens in etwa was was ist. Das mti dem char klappt so nicht glaub ich kann ja dem char net einfach die Struktur zuweisen. Habs jetzt mal mit memmove versucht gibt bisher aber nur Blödsinn aus, naja muss ich ma schauen wo es happert.

    Habt mir beide sehr geholfeden danke!

    Eine kleine Frage haette ich noch wie beschreib ich ein Bitfeld bzw wie weise ich Variablen Binärzahlen zu ?

    0xZahl = hex
    0Zahl=Oktal
    Zahl=Dezimal
    ?=binär



  • Es gibt keine Notation für binäre Konstanten (manche Compiler unterstützen die Schreibweise '0bZahl', aber die sind vermutlich in der Minderheit), nur einige hässliche Makros, die eine Dezimalzahl als Binärzahl uminterpretieren können.

    das elegantest ist imho:

    #define bin(wert) strtoul(#wert,NULL,2)
    


  • in welcher Header datei ist die Funktion strdoul den definiert?
    Hab dazu in Google leider nichts gefunden.



  • HiFish schrieb:

    in welcher Header datei ist die Funktion strdoul den definiert?

    Sorry, solche Tippfehler kommen gelegentlich vor 😉 Die Funktion heißt strtoul() und wartet in der <stdlib.h>.



  • kann passieren danke jetzt gehts 🙂



  • Mit welcher Funktion kann ich den Zahlen in einen Char schreiben?

    Wenn ich den Header in einen char schreiben will kommt nur schmarrn dabei raus da er es mit dem ASCII code dekodiert 1010 ist dann z.b. das Enter. Ich will ja aber nicht Enter sondern 1010 ausgeben.

    Mir ist klar das x[0]="1010" geht aber wie geht es wenn ich die Zahl in einer Variablen habe?



  • Schau mal in die C++ FAQ zum Thema "Einmal String nach Zahl und zurück" - dort sind auch C-taugliche Lösungsansätze eingetragen.



  • ok danke habe dort das "sprintf()" gefunden damit geht es halb immerhin kann ich so dezimalzahlen ausgeben also "10" anstatt "Enter" oder "1010", aber ich will ja die Bits ausgeben, hab allerdings nicht gefunden wie das gehen soll.

    Daraufhin habe ich mir ueberlegt die Bytes einzeln aus dem Speicher zu lesen um diese dann in Bits umzuwandeln. Das müßte ja eigentlich funktionieren.

    Gibt es da schon vorgefertigte Funktion die Dezimal in Binär umrechnen?



  • In der C Standardbiblithek - nein.

    Aber hier im Forum dürften inzwischen einige Funktionen dafür gepostet worden sein, schau dich einfach mal auf den ersten Seiten des Boards nach "binär" um.

    Edit: Eine Möglichkeit ist z.B. das hier (ist zwar C++, aber das kannst du sicher auch auf C umsetzen)



  • Oh das hab ich zu spät gesehen habs nun schon selber geschrieben allerdings gibts Probleme. Und zwar wenn ein Byte eingelesen wird bei dem das Vorzeichenbit 1 ist (Alle Bytes bei dennen das High Nibble >7 ist).
    Ich denke es liegt an der Zeile. Ein char Array kann ja leider nicht unsigned sein.

    tmp_int=(unsigned int)tmp[i];
    

    Ich hab mir mal ausgeben lassen was in dem Char Array an der Stelle steht bei 0xFF ist -1. Ich hab nun leider gar keine Idee wie ich das da rausbekommen soll der Typcast auf unsigned Int hat nichts gebracht.

    Gekürzter Quellcode

    void hdr_reader2(struct tcphdr *hdr)
    {
    	unsigned int 	size = (int)sizeof(struct tcphdr),
    			i=0,
    			tmp_int;
    
    	char 	tmp_hdr[160],
    		tmp_char[50],
    		date[20],
    		tab[1],
    		tmp2[200],
    		tmp[50];
    
    	memmove(tmp,hdr,20);
    	//printf("%d\n",size);
    	while(size)
    	{
    		tmp_int=(unsigned int)tmp[i];
    
    		tmp_hdr[i]=0;
    		tmp_hdr[i+1]=0;
    		tmp_hdr[i+2]=0;
    		tmp_hdr[i+3]=0;
    		tmp_hdr[i+4]=0;
    		tmp_hdr[i+5]=0;
    		tmp_hdr[i+6]=0;
    		tmp_hdr[i+7]=0;
    
    		printf("%d %d %d\n\n",tmp[i],tmp_int,i);
    
    		if(tmp_int>=128)
    		{
    			tmp_hdr[i*8+7]=1;
    			tmp_int-=128;
    		}if(tmp_int>=64)
    		{
    			tmp_hdr[i*8+6]=1;
    			tmp_int-=64;
    		}if(tmp_int>=32)
    		{
    			tmp_hdr[i*8+5]=1;
    			tmp_int-=32;
    		}if(tmp_int>=16)
    		{
    			tmp_hdr[i*8+4]=1;
    			tmp_int-=16;
    		}if(tmp_int>=8)
    		{
    			tmp_hdr[i*8+3]=1;
    			tmp_int-=8;
    		}if(tmp_int>=4)
    		{
    			tmp_hdr[i*8+2]=1;
    			tmp_int-=4;
    		}if(tmp_int>=2)
    		{
    			tmp_hdr[i*8+1]=1;
    			tmp_int-=2;
    		}if(tmp_int>=1)
    		{
    			tmp_hdr[i*8]=1;
    			tmp_int-=1;
    		}	
    
    		i++;
    		printf("Byte %d Fertig\n",i);
    		size--;
    	}
    }
    


  • HiFish schrieb:

    unsigned int 	size = (int)sizeof(struct tcphdr),
    

    überprüf' mal, ob da auch die erwartete länge drin steht.

    btw: ich würde ja auf die 'struct tcphdr' ganz verzichten und stattdessen immer ein 'unsigned char array' nehmen. bei einem tcp header ist genau festgelegt, wo die einzelnen felder sind, welche länge sie haben, welche byte order usw. ein c-compiler kann zwischen die struct-members füllbytes setzen, multibyte-werte falsch herum speichern, bitfields verdrehen und ähnliche schweinereien, so dass garnix mehr passt...



  • ja da kommt 20 raus so groß wie die Struktur definiert ist aber ich werds dann ma direkt auf 20 setzen 🙂

    Edit: Ja die Struktur is ja so vordefiniert die kann ich net einfach austauschen.



  • HiFish schrieb:

    Edit: Ja die Struktur is ja so vordefiniert die kann ich net einfach austauschen.

    warum das? welch mieses programm braucht so eine struct mit endian-abhängigen bitfields? 😮



  • Der Linux Kernel.



  • Hi Fish schrieb:

    Der Linux Kernel.

    hätt' ich mir denken können 😞 😡



  • Ja kann halt schlecht das ganze THCP Protokoll da umschreiben 😉 Ist allerdings auch schon ein recht alter Kernel (2.4.21).

    So nach ein bißchen rumprobieren habe ich herausgefunden das dieser "Bug", daraus resultiert das ich den Memorybereich in ein Char Array kopiere, wenn ich ihn in ein unsigned short int kopiere gibt er die richtigen Zahlen aus, allerdings ist der short 2 Byte lang.
    Ich werds jetztmal probieren indem ich das High bzw Low Byte mittels eines Logischen Unds maskiere.



  • HiFish schrieb:

    ...das dieser "Bug", daraus resultiert das ich den Memorybereich in ein Char Array kopiere, wenn ich ihn in ein unsigned short int kopiere gibt er die richtigen Zahlen aus...

    dann nimm doch 'unsigned char'
    im tcp header sind sowieso keine signed werte.
    beispiel:

    typedef unsigned long ul;
    #define READ32(p) (((ul)*(p))<<24|((ul)*(p+1))<<16|((ul)*(p+2))<<8|((ul)*(p+3)))
    
    void hdr_reader (struct tcphdr *hdr)
    { 
       unsigned char *p = (unsigned char*)hdr;         // als unsigned char array interpretieren
    
       // ip adressen
       unsigned long source_a = *(unsigned long*)p;    // architekturabhängig
       unsigned long dest_a = *(unsigned long*)(p+4);  // architekturabhängig
       // nochmal, aber...
       unsigned long source_b = READ32(p);             // network byte order 
       unsigned long dest_b = READ32(p+4);             // network byte order
       // ^^
       // was davon richtig ist, haengt davon ab, wie die struct gefüllt wird...
    ...
    ...
    }
    

Anmelden zum Antworten