Forum: Mikrocontroller und Digitale Elektronik Ping mit Webserver von U. Radig ausführen. Aber wie?


von Felix T. (felix)


Lesenswert?

Hallo Zusammen

Ich nutze den von G. Menke angepassten Webserver von U. Radig auf meinem 
AVR NET IO: 
http://www.mikrocontroller.net/articles/AVR_Net-IO_Bausatz_von_Pollin#Webserver_von_G._Menke
Das funktioniert soweit auch ganz gut.

Nun möchte ich, dass der NET IO regelmäßig eine IP bei mir im LAN 
anpingt (192.168.1.107) und prüft ob die IP erreichbar ist. Leider habe 
ich bisher nicht ganz kapiert wie die wohl dafür zuständige Funktion 
command_ping() aufgerufen werden muss, und an welcher Stelle dann auch 
das Resultat (ping erfolgreich oder nicht erfolgreich) im Programm 
erscheint.
1
// Sende "Ping" an angegebene Adresse
2
void command_ping (void)
3
{
4
  if (*((unsigned int*)&variable[0]) != 0x00000000)
5
  {
6
    (*((unsigned long*)&ping.ip1[0])) = ((variable[0])+((unsigned long)(variable[1])<<8)+((unsigned long)(variable[2])<<16)+((unsigned long)(variable[3])<<24));
7
    //ARP Request senden
8
    arp_request ( (*(unsigned long*)&ping.ip1[0]));
9
    
10
    //ICMP-Nachricht Type=8 Code=0: Echo-Anfrage
11
    //TODO: Sequenznummer, Identifier 
12
    icmp_send( (*(unsigned long*)&ping.ip1[0]),0x08,0x00,1,1);
13
  }
14
}

Meine bisherigen Versuche mit der Funktion waren nicht erfolgreich. Ich 
versteh auch den Sinn der ersten Zeile nicht so richtig:
1
 if (*((unsigned int*)&variable[0]) != 0x00000000)
Also, dass variable[0] nicht gleich 0 sein darf ist mir klar. Aber was 
bedeuten die * und warum wird hier überhaupt die variable geprüft?

Dann hab ich einfach mal alles auskommentiert bis auf die Zeile
1
 icmp_send( (*(unsigned long*)&ping.ip1[0]),0x08,0x00,1,1);
 welche ich dann leicht verändert aufgerufen habe mit
1
// Sende "Ping" an angegebene Adresse
2
void command_ping (void)
3
{
4
  //if (*((unsigned int*)&variable[0]) != 0x00000000)
5
  //{
6
  //  (*((unsigned long*)&ping.ip1[0])) = ((variable[0])+((unsigned long)(variable[1])<<8)+((unsigned long)(variable[2])<<16)+((unsigned long)(variable[3])<<24));
7
    //ARP Request senden
8
  //  arp_request ( (*(unsigned long*)&ping.ip1[0]));
9
    
10
    //ICMP-Nachricht Type=8 Code=0: Echo-Anfrage
11
    //TODO: Sequenznummer, Identifier 
12
    icmp_send( 0xC0A8016B,0x08,0x00,1,1); //0xC0A8016B = 192.167.1.107
13
  //}
14
}

Meine Erwartung war dann, dass in der main-Schleife folgende Funktion:
1
        if(ping.result)
2
        {
3
            usart_write("Get PONG: %i.%i.%i.%i\r\n",ping.ip1[0],ping.ip1[1],ping.ip1[2],ping.ip1[3]); 
4
            ping.result = 0;
5
        }
dann über UART den Hinweis ausgegeben hätte. Leider kommt da gar nichts 
:-(
Der UART funktioniert aber, das habe ich natürlich vorher getestet. Und 
192.168.1.107 lässt sich auch problemlos von einem PC im Netzwerk 
anpingen.
Wie wichtig ist die Funktion
1
 arp_request ( (*(unsigned long*)&ping.ip1[0]));
? Darf ich die einfach so auskommentieren? Laut Wikipedia 
http://de.wikipedia.org/wiki/Ping_(Daten%C3%BCbertragung)#Funktionsweise 
reicht send_icmp().

Könnt ihr mir weiterhelfen? Vielen Dank schon mal.

Gruß, Felix

: Bearbeitet durch User
von Karl K. (leluno)


Lesenswert?

ich kann dir nicht weiterhelfen, stehe aber mit meinem webserver genau 
vor dem gleichen problem wie du: Wie sendet man irgendetws vom 
webserver?

die funktion arp_request kannst du sicher nicht weglassen. die 
arp-tabelle steuert den datenaustausch.

Ich versuche gerade den Stack-speicher >eth_buffer< auszulesen. das echo 
auf den ping müsste über diesen empfangen werden.

von leluno (Gast)


Lesenswert?

es gibt ein Netzwerk-Analysetool
http://www.wireshark.org/download.html
Ist vielleicht hilfreich

von Felix T. (felix)


Lesenswert?

Zumindest bin ich schon mal nicht alleine mit meinem Problem :-)

Die Idee mit wireshark ist nicht schlecht. Ich hoffe, dass ich heute 
Abend dazu komme und ein paar neue Erkenntnisse gewinne.

Trotzdem hier nochmal der Aufruf an die die wissen wie das Ganze 
funktioniert: ein kleiner Tipp von euch wäre super :-)

von Karl H. (kbuchegg)


Lesenswert?

Na ja.
 So schwer kann das aber nicht sein

variable ist offensichtlich ein Eingangswert, höchst wahrscheinlich sind 
das die Werte, die über die COmmand line eingegeben werden.
Eine Command Line von
"ping 192.168.0.97"
führt zu
1
variable[0]  192
2
variable[1]  168
3
variable[2]  0
4
variable[3]  97

Die einzige Frage, die sich stellt ist, ist die Reihenfolge genau so 
oder genau anders rum. Das lässt sich aber rauskriegen, in dem man 
einfach mal eine Debug Ausgabe in den Code einbaut, flasht und über die 
Command Line einen ping eingibt.


D.h. hier
1
  if (*((unsigned int*)&variable[0]) != 0x00000000)

wird geprüft, ob es eine eingabe gab, denn der Benutzer könnte ja auch 
einfach
"ping"
eingegeben haben, und dann soll nichts schlimmes passieren.

Hier
1
    (*((unsigned long*)&ping.ip1[0])) = ((variable[0])+((unsigned long)(variable[1])<<8)+((unsigned long)(variable[2])<<16)+((unsigned long)(variable[3])<<24));
wird aus der Eingabe die intern verwendete IP-Adresse zusammengebaut, 
indem das Array ping.ip1 als unsigned long aufgefasst wird (4 Bytes). 
Der rechte Teil der Zuweisung ist einfach nur das Zusammenstoppeln der 4 
Einzelbytes zu einem derartigen unsigned long.
Man hätte die Bytes auch direkt zuweisen können, hätte aber dann darauf 
achten müssen, dass die Bytereihenfolge korrekt ist. So erledigt das der 
COmpiler und zeitkritisch ist es an dieser Stelle auch nicht.

hier
1
    //ARP Request senden
2
    arp_request ( (*(unsigned long*)&ping.ip1[0]));
3
    
4
    //ICMP-Nachricht Type=8 Code=0: Echo-Anfrage
5
    //TODO: Sequenznummer, Identifier 
6
    icmp_send( (*(unsigned long*)&ping.ip1[0]),0x08,0x00,1,1);

wird dann der Ping abgesetzt, dessen Antwort dann über die anderweitigen 
üblichen Kanäle eingeholt wird.

Willst du also per Programm 192.168.1.107 anpingen, dann würde ich mir 
dafür eine Funktion schreiben
1
void pingTo( uint8_t ip1, uint8_t ip2, uint8_t ip3, uint8_t ip4 )
2
{
3
  (*((unsigned long*)&ping.ip1[0])) = ( ip1 +
4
                                       ((unsigned long)ip2 << 8) +
5
                                       ((unsigned long)ip3 << 16) +
6
                                       ((unsigned long)ip4 << 24) );
7
8
  //ARP Request senden
9
  arp_request ( (*(unsigned long*)&ping.ip1[0]));
10
    
11
  //ICMP-Nachricht Type=8 Code=0: Echo-Anfrage
12
  //TODO: Sequenznummer, Identifier 
13
  icmp_send( (*(unsigned long*)&ping.ip1[0]),0x08,0x00,1,1);
14
}

und dann eben
1
   ....
2
   pingTo( 192, 168, 1, 107 );
3
   ....

ich geh mal davon aus, dass 'ping' eine globale Variable ist, die 
benötigt wird, damit bei der empfangenen Antwort die entsprechende 
Ausgabe gemacht werden kann.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

>  und an welcher Stelle dann auch das Resultat (ping erfolgreich oder nicht 
erfolgreich)

Wie das beim Menke Server ist weiß ich nicht.
Aber der COde vom Radig Ulrich schreibt als Antwort 'PONG' hin. Wenn du 
also nach dem Text suchst, müsstest du die Stelle im Code finden, an der 
die Antwort eintrudelt und ausgewertet wird bzw. wo dann entschieden 
wird, ob der ping als 'in den Timeout gelaufen' deklariert wird und aus 
der Liste der offenen Pakete ausgetragen wird.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:

> und dann eben
>
1
> 
2
>    ....
3
>    pingTo( 192, 168, 1, 107 );
4
>    ....
5
>

und wenn ichs mir recht überlege, ist auch das eigentlich noch zu 
kompliziert wenn die anzupingende IP sowieso fix ist
1
void pingClient()
2
{
3
  variable[0] = 192;
4
  variable[1] = 168;
5
  variable[2] = 1;
6
  variable[3] = 107;
7
8
  command_ping();
9
}

viel einfacher.
Vorher aber mit einer Debug Ausgabe kontrollieren, ob die Reihenfolge 
vom Command Line Prozessor tatsächlich so eingestellt wird.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Das hier (stack.c)
1
//Check Packet and call Stack for TCP or UDP
2
void check_packet (void)
3
{
4
....
5
6
                arp_entry_add();  ///Refresh des ARP Eintrages
7
                if(ip->IP_Proto == PROT_ICMP)
8
                {
9
                    switch ( icmp->ICMP_Type )
10
                    {
11
                        case (8): //Ping reqest
12
                            icmp_send(ip->IP_Srcaddr,0,0,icmp->ICMP_SeqNum,icmp->ICMP_Id); 
13
                            break;
14
                            
15
                        case (0): //Ping reply
16
                            if ((*((unsigned long*)&ping.ip1[0])) == ip->IP_Srcaddr)
17
                            {
18
                                ping.result |= 0x01;
19
                            }
20
                            DEBUG("%i",    (ip->IP_Srcaddr&0x000000FF)     );
21
                            DEBUG(".%i",  ((ip->IP_Srcaddr&0x0000FF00)>>8 ));
22
                            DEBUG(".%i",  ((ip->IP_Srcaddr&0x00FF0000)>>16));
23
                            DEBUG(".%i :",((ip->IP_Srcaddr&0xFF000000)>>24));
24
                            break;
25
                    }
26
                    return;
scheint die Stelle zu sein, an der die ICMP Antwort ausgewertet wird. 
Wenn sie reichtig ist, wird ping.result auf 1 gesetzt.
Jetzt muss man noch finden, wo diese 1 ausgewertet wird.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Da haben wirs schon.

main.c
1
int main()
2
{
3
  ....
4
5
  while(1)
6
  {
7
....
8
9
10
        if(ping.result)
11
        {
12
            usart_write("Get PONG: %i.%i.%i.%i\r\n",ping.ip1[0],ping.ip1[1],ping.ip1[2],ping.ip1[3]); 
13
            ping.result = 0;
14
        }
15
    }//while (1)

von Karl H. (kbuchegg)


Lesenswert?

Wobei das hier

> %i.%i.%i.%i\r\n",ping.ip1[0],ping.ip1[1],ping.ip1[2],ping.ip1[3]

eine Möglichkeit eröffnet, wie man diesen ganzen unsigned long 
Palawatsch gar nicht braucht.
Ich denke, da waren sich die Autoren selbst nicht einig, wie das laufen 
soll, bzw. sie haben hier bei den Funktionen
 arp_request ( ... )
 icmp_send( ... )
nicht gut genug überlegt, wie sie die Parameterübergabe machen wollen.

Da fehler eine Struktur, die einzig und alleine den Zweck hat, eine 
IP-Adresse in Form von 4 Bytes zu speichern (vielleicht gibt es die 
sogar irgendwo, müsste man im Code stöbern), und dann sowas anstelle des 
unsigned long zu übergeben. Sowas ist sowieso eine Unsitte, wie man 
spätestens beim Anstieg der CPU-Bitzahlen seit einigen Jahren immer 
wieder deutlich merkt.

: Bearbeitet durch User
von Felix T. (felix)


Lesenswert?

Hallo Zusammen

Hat leider etwas länge gedauert bis ich dazu gekommen bin es 
auszuprobieren.

Im Grunde genommen ist es eigentlich ganz einfach. Man muss einfach über 
ein Terminal via RS232 an den Net-IO den Textstring "ping 192.168.1.107" 
senden (gefolgt von einem \CR). Lässt sich die IP anpingen kommt im 
Terminal die Pong-Antwort.
@kbuchegg: danke für deinen Hinweis, der hat mich darauf gebracht.

Über ein bisschen rumprobieren und debuggen habe ich die Ping-Funktion 
nun für meine Zwecke entfremden können :-)

Vielen Dank euch nochmal.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.