› Foros › PC › Software libre
//----------------------------------------------------------------------------
//Check Packet and call Stack for TCP or UDP
#define ETHER_OFFSET 0x00
#define IP_OFFSET 0x0E
#define MTU_SIZE 600
unsigned char eth_buffer[MTU_SIZE+1];
void check_packet (void)
{
struct Ethernet_Header *ethernet; //Pointer auf Ethernet_Header
struct IP_Header *ip; //Pointer auf IP_Header
ethernet = (struct Ethernet_Header *)ð_buffer[ETHER_OFFSET];
ip = (struct IP_Header *)ð_buffer[IP_OFFSET];
if(ethernet->EnetPacketType == HTONS(0x0806) ) //ARP
{
arp_reply(); // check arp packet request/reply
}
else
...
ethernet = (struct Ethernet_Header *)ð_buffer[ETHER_OFFSET];
manugarrote escribió:La pregunta es, ¿qué hace esta linea?ethernet = (struct Ethernet_Header *)ð_buffer[ETHER_OFFSET];
Jan@work escribió:manugarrote escribió:La pregunta es, ¿qué hace esta linea?ethernet = (struct Ethernet_Header *)ð_buffer[ETHER_OFFSET];
Aparentemente hace que la estructura que tienes, llamada "ethernet", apunte a la direccion de memoria del array de chars llamado eth_buffer, en su posicion inicial (porque ETHER_OFFSET esta definido como 0);
En la siguiente linea repite, pero como es la estructura del paquete IP, apunta a una posicion mas avanzada de ese mismo array, donde empieza el paquete IP dentro de la trama Ethernet.
ethernet->EnetPacketType=(0xFFFF);
ethernet->EnetPacketSrc[0]='A';
manugarrote escribió:Otra cuestión. Si yo voy rellenando las distintas variables de la estructura, por ejemplo utilizando los punteros a estructuras así:ethernet->EnetPacketType=(0xFFFF);
ethernet->EnetPacketSrc[0]='A';
¿Cómo se ordenarían en memoria? Es decir, si el puntero ethernet apunta a la primera posición del vector eth_buffer, ¿dónde se meterían el resto de campos de la estructura? Me imagino que sea en las posiciones de memoria contiguas (ocupando cada una dependiendo de su tipo de variable).
GRACIAS!!!
#include <stdio.h>
struct miestructura {
char caracter;
int entero;
} prueba;
#define INICIO 0x00
unsigned char vector[10];
void funcion (void)
{
struct miestructura *prueba; //Puntero a una variable estructura tipo "miestructura"
prueba = (struct miestructura *)&vector[INICIO];//Apunta a la dirección 0 de mi vector
prueba->caracter='A'; //relleno los campos
prueba->entero=6; //relleno los campos
}
int main ()
{
funcion();
for (int i=0;i<10;i++)
printf("%i ",vector[i]);//Imprimo mi vector
}
65 0 0 0 6 0 0 0 0 0
manugarrote escribió:He estado haciendo pruebas con este código, para ver si lo entendía, pero no soy capaz:#include <stdio.h>
struct miestructura {
char caracter;
int entero;
} prueba;
#define INICIO 0x00
unsigned char vector[10];
void funcion (void)
{
struct miestructura *prueba; //Puntero a una variable estructura tipo "miestructura"
prueba = (struct miestructura *)&vector[INICIO];//Apunta a la dirección 0 de mi vector
prueba->caracter='A'; //relleno los campos
prueba->entero=6; //relleno los campos
}
int main ()
{
funcion();
for (int i=0;i<10;i++)
printf("%i ",vector[i]);//Imprimo mi vector
}
Tras compilar y ejecutar me sale ésto:65 0 0 0 6 0 0 0 0 0
¿No me deberían salir el 65 y el 6 pegados?
#pragma pack(push,1)
struct miestructura {
char caracter;
int entero;
} prueba;
#pragma pack(pop)
En teoria si, pero en la practica el compilador alinea la estructura que estas declarando con un padding de 4 bytes (osea que alinea las variables para que empiezen en posiciones de memoria multiplos de 4) para que tenga un mejor rendimiento al acceder a las variables en memoria. Esto nunca lo vas a notar a menos que intentes hacer un cast como el que acabas de hacer. En fin, la solución para que el compilador no ponga el padding es diciendole mediante una opción de preporcesador que no haga (o mejor dicho que lo haga con un padding de 1 byte):#pragma pack(push,1)
struct miestructura {
char caracter;
int entero;
} prueba;
#pragma pack(pop)
Esto es usado mucho por ejemplo cuando tienes que leer/escribir vectores de bytes con/en una estrcutura. De hecho me imagino que la estructura "Ethernet_Header" que pones más arriba debe tener los modificadores de padding que menciono si usa campos de tipo int, char, etc.
#include <stdio.h>
#pragma pack(push,1)
struct miestructura {
unsigned char caracter;
unsigned int entero;
unsigned long largo;
} prueba;
#pragma pack(pop)
#define INICIO 0x00
unsigned char vector[10];
void funcion (void)
{
struct miestructura *prueba; //Puntero a una variable estructura tipo "miestructura"
prueba = (struct miestructura *)&vector[INICIO];//
prueba->caracter=0xFF;
prueba->entero=0xFFFF;
prueba->largo=0xFFFFFFFF;
}
int main ()
{
funcion();
for (int i=0;i<10;i++)
printf("%i ",vector[i]);
}
255 255 255 0 0 255 255 255 255 0
manugarrote escribió:En ese ejemplo vale, pero he probado a meter otra variable en la estructura (una tipo long para tener 8, 16 y 32 bits). He puesto la instrucción para el preprocesador que me has dicho, pero no funciona.
codestation escribió:manugarrote escribió:En ese ejemplo vale, pero he probado a meter otra variable en la estructura (una tipo long para tener 8, 16 y 32 bits). He puesto la instrucción para el preprocesador que me has dicho, pero no funciona.
Un int no es siempre 16 bits ni el long de 32 bits, eso ya depende de la arquitectura a la cual estés compilando (imprime los valores de sizeof(int) y sizeof(long) para que te des cuenta). Por ejemplo en un x86 el int y el long es de 32 bits, pero en amd64 el int sigue siendo de 32 bits mientras que el long es de 64 bits. Viniendo por ese camino tus asignaciones del valor maximo al int y long no siempre van a ser las correctas dependiendo de la arquitectura a la cual compiles.
manugarrote escribió:Ok!! Mi programa es para una arquitectura muy concreta (un microcontrolador), pero lo tendré en cuenta a la hora de hacer la pila, para que sea compatible con los que tengan distinto tamaño de palabra.
De todas formas, ¿por qué no ha funcionado la instrucción del preprocesador?
prueba->entero=0xFFFF;
255 255 255 0 0 255 255 255 255 0
| char | int | long |
codestation escribió:La salida que estas posteando es del código compilado para el microcontrolador o compilando genericamente con el compilador de tu SO?
Si es lo segundo: la instrucción de preprocesador ha funcionado, pero lo que pasa es que no has "llenado" completamente el int:prueba->entero=0xFFFF;
En esa parte solo llenas 16 bits, lo cual puede funcionar en tu microcontrolador (asumiendo que el int tenga 16 bits allí), pero no si lo estás compilando para correrlo en tu SO, en el cual el int es de 32 bits.
manugarrote escribió:Cierto, antes de ller tu respuesta he estado "jugando" y he visto que en mi PC, tanto el int, como el long ocupan 32 bits.
Una pregunta más, y creo que te dejo en paz por hoy. El tamaño de las variables viene impuesto por la arquitectura del micro, ¿no se puede hacer dada al respecto?
PD: muchísimas gracias por tu paciencia me has sido de una GRAN ayuda!!
struct miestructura {
unsigned char caracter;
uint16_t entero;
uint32_t largo;
} prueba;
#include <stdio.h>
#include <stdlib.h>//Para generar el nº aleatorio
#include <stdint.h>//Para tipos de datos raros
#pragma pack(push,1)
struct IP_Header {
unsigned char IP_Vers_Len; //8 Bits (Versión + Tamaño cabecera)
unsigned char IP_Tos; //8 Bits Type of Service
uint16_t IP_Pktlen; //16 Bits
uint16_t IP_Id; //16 Bits
uint16_t IP_Frag_Offset; //16 Bits (Flags + Posición del fragmento)
unsigned char IP_ttl; //8 Bits
unsigned char IP_Proto; //8 Bits
uint16_t IP_Hdr_Cksum; //16 Bits Checksum
uint32_t IP_Srcaddr; //32 Bits IP Fuente
uint32_t IP_Destaddr; //32 Bits IP Destino
};
#pragma pack(pop)
#define IP_OFFSET 0x00
//#define MTU_SIZE 600 //(Maximum Transfer Unit) unidad máxima de transferencia
#define MTU_SIZE 10 //Para pruebas
#define RAND_MAX 255 //Para pruebas
unsigned char buffer[MTU_SIZE+1];
void check_packet (void)
{
struct IP_Header *ip; //Puntero a tipo IP_Header
ip = (struct IP_Header *)&buffer[IP_OFFSET];//Puentero en la Posición IP de la trama
printf("%c ",ip->IP_Vers_Len);
printf("%c ",ip->IP_Tos);
printf("%c ",ip->IP_Pktlen);
printf("%c ",ip->IP_Id);
printf("%c ",ip->IP_Frag_Offset);
printf("%c ",ip->IP_ttl);
printf("%c ",ip->IP_Proto);
printf("%c ",ip->IP_Hdr_Cksum);
printf("%c ",ip->IP_Srcaddr);
printf("%c ",ip->IP_Destaddr);
}
int main ()
{
for (int i=0;i<(MTU_SIZE);i++){ //-----------------------------------------------
buffer[i]=rand(); // Generamos y mostramos una cabecera aleatoria
printf("%c ",buffer[i]);} //-----------------------------------------------
printf("\n");
check_packet();
}
) # ¥ ä ß l Í « R É
) # ¥ ß Í R É
manugarrote escribió:A la salida tengo:) # ¥ ä ß l Í « R É
) # ¥ ß Í R É
Hay algunos caracteres que no se representan y no sé por qué.
GRACIAS!!!
codestation escribió:Bueno, estás llenando el vector de datos "aleatorios" y luego los imprimes a caracteres, me sorprendería lo contrario . Mucho mejor seria que mostraras la data en HEX por lo menos para que pudieras ver los datos y comparar mejor. Mirate mejor "man 3 printf" o busca por internet como dar un mejor formato a lo que intentas mostrar por consola.
29 23 be 84 e1 6c d6 ae 52 90
29 23 84be 6ce1 aed6 52 90 0 0 0
manugarrote escribió:codestation escribió:Bueno, estás llenando el vector de datos "aleatorios" y luego los imprimes a caracteres, me sorprendería lo contrario . Mucho mejor seria que mostraras la data en HEX por lo menos para que pudieras ver los datos y comparar mejor. Mirate mejor "man 3 printf" o busca por internet como dar un mejor formato a lo que intentas mostrar por consola.
Ayer busqué los argumentos que se le podían pasar a printf porque me olía que el problema podría ser de eso, pero no encontré tanta información como la que tu me has dicho.
He probado con el identificador x y algo hemos avanzado. Ahora la salida es ésta:29 23 be 84 e1 6c d6 ae 52 90
29 23 84be 6ce1 aed6 52 90 0 0 0
Por lo que se puede apreciar que algo falla, que estoy cerca de dar con la solución pero no termino de entender por qué falla (sólo con mis datos de 16bits) ni como solucionarlo.
PD: gracias por tu paciencia.
unsigned char EnetPacketDest[6];
unsigned char EnetPacketSrc[6];
manugarrote escribió:Ya que tengo el hilo abierto y es una duda de C lo pregunto aquí.
Tengo 2 arrays de caracteres, pongamos que son:unsigned char EnetPacketDest[6];
unsigned char EnetPacketSrc[6];
Quiero intercambiar sus valores, es decir, que EnetPacketDest tenga los valores de EnetPacketSrc y viceversa. He intentado hacerlo utilizando un puntero como temporal para almacenar la dirección de memoria, pero el compilador me ha dicho que soy un borrico, literalmente "ISO C++ forbids assignment of arrays".
Una forma que se me ocurre de hacerlo es crean un array auxiliar, utilizar un bucle para copiar los valores del EnetPacketDest y luego otro bucle para copiar del auxiliar al EnetPacketSrc.
¿Hay alguna forma más elegante de hacer esto? Gracias!!!
char *p;
char v[3] = {'a', 'b','c'};
p = v;
Yog-Sothoth escribió:Pues no sé como lo habrás hecho, pero a mi sí me deja asignar un vector a un puntero. De hecho la manera que tiene C de tratar apuntadores y vectores es bastante similar, de manera que puedes trabajar con arrays como si fueran punteros y viceversa. El nombre del vector equivaldría a la primera posición del vector a la que le puedes ir sumando un desplazamiento para acceder a los demás elementos, etc => v[i] == *(v + i)char *p;
char v[3] = {'a', 'b','c'};
p = v;
Saludos:).
manugarrote escribió:El problema viene a la hora de asignar al vector la dirección del puntero
unsigned char temporal[6];
for (int i=0;i<6;i++){
temporal[i]=ethernet->EnetPacketDest[i];
ethernet->EnetPacketDest[i]=ethernet->EnetPacketSrc[i];
ethernet->EnetPacketSrc[i]=temporal[i];
}
manugarrote escribió:AL final lo he dejado así:unsigned char temporal[6];
for (int i=0;i<6;i++){
temporal[i]=ethernet->EnetPacketDest[i];
ethernet->EnetPacketDest[i]=ethernet->EnetPacketSrc[i];
ethernet->EnetPacketSrc[i]=temporal[i];
}
Mi profesor dice que programando soy muy práctico pero poco elegante
for (int i=0;i<6;i++){
ethernet->EnetPacketDest[i] ^= ethernet->EnetPacketSrc[i];
ethernet->EnetPacketSrc[i] ^= ethernet->EnetPacketDest[i];
ethernet->EnetPacketDest[i] ^= ethernet->EnetPacketSrc[i];
}
codestation escribió:Ten en cuenta que no necesitas todo un vector auxiliar para hacer el swap, de hecho con sola una variable simple bastaría.
EDIT: como alternativa, en este caso especifico también puedes omitir el usar una variable auxiliar usando la operación XORfor (int i=0;i<6;i++){
ethernet->EnetPacketDest[i] ^= ethernet->EnetPacketSrc[i];
ethernet->EnetPacketSrc[i] ^= ethernet->EnetPacketDest[i];
ethernet->EnetPacketDest[i] ^= ethernet->EnetPacketSrc[i];
}
Ferdy escribió:http://en.wikipedia.org/wiki/XOR_swap_algorithm
En concreto lee con detenimiento la parte de "Reasons for avoidance in practice.".
Este también es interesante: http://big-bad-al.livejournal.com/98093.html (está enlazado en la propia página de Wikipedia)
Saludos.