]> git.llucax.com Git - z.facultad/66.09/etherled.git/commitdiff
Listo el cálculo de checksum de IP.
authorLeandro Lucarella <llucax@gmail.com>
Mon, 14 Nov 2005 02:08:18 +0000 (02:08 +0000)
committerLeandro Lucarella <llucax@gmail.com>
Mon, 14 Nov 2005 02:08:18 +0000 (02:08 +0000)
src/c/eth.c
src/c/ip.c
src/c/types.h
src/c/udp.c

index 83805b76fb11647205deab32d36c8c257c62ef8c..5c8686f9cb650c453c43df7a8dca5eb73f4f6e04 100644 (file)
@@ -40,8 +40,6 @@ void eth_write_frame_header()
 {
        /* variable para iterar */
        byte i;
-       /* tipo de paquete transportado */
-       uint16 type = ;
        /* mandamos como MAC de destino la remota */
        for (i = 0; i < ETH_MAC_SIZE; ++i)
                net_putb(mac_addr_remote[i]);
index 44dd1ac78fbcaefe9a043e128ab6e5efefd13a4c..b9f5fb48dd6b9b7749e8ccba13ff0228759ef818 100644 (file)
@@ -11,37 +11,55 @@ byte ip_packet_len;
 
 bool ip_proto_icmp;
 
+uint16 checksum;
+
+static void sum(uint16 w)
+{
+       checksum += w;
+       if (checksum < w) /* corrección de carry (hubo OV) */
+               ++checksum;
+}
+
 bool ip_read_packet_header()
 {
-       /* variable para utilitaria (iterar y/o buffer) */
-       byte c;
+       /* variables utilitarias (iterar y/o buffer) */
+       byte h, l;
+       /* reseteamos checksum */
+       checksum = 0;
        /* versión y tamaño de cabecera vienen en el 1er byte */
-       c = net_getb();
+       h = net_getb();
        /* sólo soportamos versión 4 */
-       if ((c >> 4) != 4)
+       if ((h >> 4) != 4)
                return false; /* drop */
        /* tamaño de cabecera */
-       if ((c & 0x0F) != 5) /* no aceptamos opciones raras =) */
+       if ((h & 0x0F) != 5) /* no aceptamos opciones raras =) */
                return false; /* drop */
-       /* ignoramos el TOS */
-       net_getb();
+       /* ignoramos el TOS y vamos calculando checksum */
+       sum(WORD(h, net_getb()));
        /* obtenemos tamaño del paquete */
-       if (net_getb()) /* tiene más de 255 bytes (no lo soportamos) */
+       if (h = net_getb()) /* tiene más de 255 bytes (no lo soportamos) */
                return false; /* drop */
        ip_packet_len = net_getb(); /* hasta 255 bytes tienen los nuestros */
-       /* ignoramos identificación */
-       net_getb(); net_getb(); /* 2 bytes */
+       /* vamos calculando checksum */
+       sum(WORD(h, ip_packet_len));
+       /* ignoramos identificación (2 bytes) y vamos calculando checksum */
+       sum(net_getw());
        /* si tiene prendido el bit de MF (More Fragments, bit 5 del byte, bit 2
         * de los flags de la cabecera) o si tiene un offset de fragmento (bits
         * del 4 al 0 y todos los bits del byte siguiente), dropeamos (no
         * soportamos fragmentación) */
-       if (net_getw() & 0x3FFF)
+       h = net_getb();
+       l = net_getb();
+       if ((h & 0x3F) || l)
                return false; /* drop */
+       /* seguimos calculando checksum */
+       sum(WORD(h, l));
        /* no le damos bola al TTL (no le vamos a hacer lío si ya llegó hasta
         * acá el pobre =) */
-       net_getb();
+       h = net_getb();
        /* protocolo (sólo soportamos UDP e ICMP) */
-       switch (net_getb())
+       l = net_getb();
+       switch (l)
        {
                case ICMP:
                        ip_proto_icmp = true;
@@ -52,49 +70,83 @@ bool ip_read_packet_header()
                default:
                        return false; /* drop */
        }
-       /* checksum */
-       net_getb(); net_getb(); /* TODO: verificar checksum */
-       /* obtenemos IP de origen */
-       for (c = 0; c < IP_ADDR_SIZE; ++c)
-               ip_addr_remote[c] = net_getb();
-       /* vemos si el paquete es para nosotros (ningún soportar broadcast =) */
-       for (c = 0; c < IP_ADDR_SIZE; ++c)
-               if (ip_addr_local[c] != net_getb()) 
-                       return false; /* no es para nosotros */
+       /* sigo calculando checksum */
+       sum(WORD(h, l));
+       /* obtenemos checksum y seguimos el cálculo */
+       sum(net_getw());
+       /* obtenemos IP de origen (mientras seguimos calculando el checksum) */
+       for (l = 0; l < IP_ADDR_SIZE; ++l)
+       {
+               ip_addr_remote[l] = net_getb();
+               if (l % 2)
+                       sum(WORD(h, ip_addr_remote[l]));
+               else
+                       h = ip_addr_remote[l];
+       }
+       /* vemos si el paquete es para nosotros (ningún soportar broadcast =)
+        * (mientras seguimos calculando el checksum) */
+       for (l = 0; l < IP_ADDR_SIZE; ++l)
+       {
+               if (ip_addr_local[l] != net_getb()) 
+                       return false; /* drop (no es para nosotros) */
+               if (l % 2)
+                       sum(WORD(h, ip_addr_local[l]));
+               else
+                       h = ip_addr_local[l];
+       }
+       /* verificamos checksum */
+       if (~checksum)
+               return false; /* checksum malo, drop */
        return true;
 }
 
 void ip_write_packet_header()
 {
-       /* variable para iterar */
-       byte i;
+       /* variables utilitarias (iterar y/o buffer) */
+       byte h, l;
        /* identificador del paquete IP (incrementa con cada paquete) */
-       static uint16 id = 0;
+       static uint16 id;
+       /* reseteamos checksum */
+       checksum = 0;
        /* versión (4) y tamaño de cabecera (5 words de 4 bytes = 20 bytes) */
-       net_putb(0x45);
-       /* TOS */
-       if (ip_proto_icmp)
-               net_putb(0xc0); /* Precedence: Internetwork Control */
-       else
-               net_putb(0x00); /* Precedence: Normal */
-       net_getb();
+       net_putb(h = 0x45);
+       /* TOS (0xc0 = Internetwork Control, 0x00 = normal) */
+       l = ip_proto_icmp ? 0xc0 : 0x00;
+       net_putb(l);
+       sum(WORD(h, l)); /* actualizamos checksum */
        /* escribimos tamaño del paquete */
-       net_putb(0x00); /* nunca vamos a mandar algo de más de 255 bytes */
+       net_putb(h = 0x00); /* nunca vamos a mandar algo de más de 255 bytes */
        net_putb(ip_packet_len);
+       sum(WORD(h, ip_packet_len)); /* actualizamos checksum */
        /* identificación (sirve para reensamblar paquetes) */
        net_putw(id);
+       sum(id); /* actualizamos checksum */
        /* pedimos que no se fragmente */
-       net_putb(0x40); /* Don't Fragment (DF) = 1 */
-       net_putb(0x00); /* offset de fragmento = 0 */
+       net_putb(h = 0x40); /* Don't Fragment (DF) = 1 */
+       net_putb(l = 0x00); /* offset de fragmento = 0 */
+       sum(WORD(h, l)); /* actualizamos checksum */
        /* TTL de 64 saltos porque está de moda */
-       net_putb(0x40);
+       net_putb(h = 0x40);
        /* protocolo (sólo soportamos UDP e ICMP) */
-       if (ip_proto_icmp)
-               net_putb(ICMP);
-       else
-               net_putb(UDP);
-       /* checksum */
-       net_putb(0x00); net_putb(0x00); /* TODO: calcular checksum */
+       l = ip_proto_icmp ? ICMP : UDP;
+       net_putb(l);
+       sum(WORD(h, l)); /* actualizamos checksum */
+       /* checksum: antes de poder escribir el checksum hay que terminar de
+        * calcularlo según las direcciones IP de origen y destino, así que eso
+        * hacemos */
+       for (l = 0; l < IP_ADDR_SIZE; ++l) /* origen = local */
+               if (l % 2)
+                       sum(WORD(h, ip_addr_local[l]));
+               else
+                       h = ip_addr_local[l];
+       for (l = 0; l < IP_ADDR_SIZE; ++l) /* destino = remota */
+               if (l % 2)
+                       sum(WORD(h, ip_addr_remote[l]));
+               else
+                       h = ip_addr_remote[l];
+       /* ahora sí grabamos el checksum */
+       net_putw(~checksum);
+       /* ahora sí, continuamos poniendo las direcciones */
        /* ponemos como dirección IP de origen la nuestra */
        for (i = 0; i < IP_ADDR_SIZE; ++i)
                net_putb(ip_addr_local[i]);
index db65dd032a973396757eae8ae53e220b40cfb999..52b07d14e6b00a7ccd1bdfd954348804eee93695 100644 (file)
@@ -4,6 +4,18 @@
 /** valores posibles de un booleano */
 enum { false = 0, true = 1 };
 
+/** convierte 2 bytes (high, low) en un word */
+#define WORD(high, low) ((high << 8) + low)
+
+/** convierte un word en 2 bytes */
+#define UNPACK(word, high, low) (high = (word >> 8), low = word)
+
+/** obtiene parte alta de un word */
+#define HIGH(word) (word >> 8)
+
+/** obtiene parte baja de un word */
+#define LOW(word) (word)
+
 #if 1 /* i386 */
 
 /** booleano */
index 1c4189e370410f91a32fe65c76ec85664fd6c30d..05dcdb13e61658a7765ecb14fb9aa640f90cb8a3 100644 (file)
@@ -8,7 +8,7 @@ extern byte udp_dgram_len;
 
 bool udp_read_dgram_header()
 {
-       /* puerto origen */
+       /* puerto origen (remoto) */
        udp_port_remote = net_getw();
        /* sólo aceptamos datagramas a nuestro puerto */
        if (net_getw() != udp_port_local)