]> git.llucax.com Git - z.facultad/66.09/etherled.git/commitdiff
Primera implementación de Ethernet+IP+UDP. Falta el chequeo y cálculo de
authorLeandro Lucarella <llucax@gmail.com>
Sun, 13 Nov 2005 22:15:13 +0000 (22:15 +0000)
committerLeandro Lucarella <llucax@gmail.com>
Sun, 13 Nov 2005 22:15:13 +0000 (22:15 +0000)
checksum de IP (que aparentemente es obligatorio). La implementación se basa en
un par de funciones aún no implementadas que puede escribir y leer un byte de la
placa de red. Esa función probablemente haya que implementarla en ASM.
Por ahora no se implementa ARP e ICMP, porque no son estrictamente necesarios
para que el proyecto sea mínimamente funcional. De todas formas son altamente
deseables (en especial el ARP) y si queda tiempo la idea sería implementarlo.
Falta también, nuestro protocolo, que se monta sobre esto.

src/c/eth.c [new file with mode: 0644]
src/c/eth.h [new file with mode: 0644]
src/c/ip.c [new file with mode: 0644]
src/c/ip.h [new file with mode: 0644]
src/c/net.h [new file with mode: 0644]
src/c/types.h [new file with mode: 0644]
src/c/udp.c [new file with mode: 0644]
src/c/udp.h [new file with mode: 0644]

diff --git a/src/c/eth.c b/src/c/eth.c
new file mode 100644 (file)
index 0000000..83805b7
--- /dev/null
@@ -0,0 +1,54 @@
+#include "eth.h"
+
+/** tipos de paquetes transportados soportados */
+enum { IP = 0x0800, ARP = 0x0806 };
+
+byte mac_addr_local[MAC_ADDR_SIZE];
+
+byte mac_addr_remote[MAC_ADDR_SIZE];
+
+bool eth_frame_arp;
+
+bool eth_read_frame_header()
+{
+       /* variable para iterar */
+       byte i;
+       /* vemos si es para nosotros */
+       for (i = 0; i < MAC_ADDR_SIZE; ++i)
+               if (mac_addr_local[i] != net_getb())
+                       return false; /* no es para nosotros (drop) */
+       /* obtenemos MAC de origen */
+       for (i = 0; i < MAC_ADDR_SIZE; ++i)
+               mac_addr_remote[i] = net_getb();
+       /* obtenemos tipo de protocolo transportado por el frame, (sólo
+        * aceptamos IP y ARP) */
+       switch (net_getw())
+       {
+               case IP:
+                       eth_frame_arp = false;
+                       break;
+               case ARP:
+                       eth_frame_arp = true;
+                       break;
+               default:
+                       return false; /* drop */
+       }
+       return true;
+}
+
+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]);
+       /* y como fuente la nuestra */
+       for (i = 0; i < ETH_MAC_SIZE; ++i)
+               net_putb(mac_addr_local[i]);
+       /* escribimos el tipo de paquete que transporta el frame */
+       net_putw(eth_frame_arp ? TYPE_ARP : TYPE_IP);
+}
+
diff --git a/src/c/eth.h b/src/c/eth.h
new file mode 100644 (file)
index 0000000..54b1f53
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef _ETH_H_
+#define _ETH_H_
+
+#include "types.h"
+#include "net.h"
+
+/** @file
+ * Estructura de un frame ethernet.
+ *
+ * <pre>
+ * /--- 8 ----/--- 6 ----/--- 6 ----/- 2 --/- 46-1500 -/- 4 -/  bytes
+ * +----------+----------+----------+------+-----------+-----+
+ * | preamble | dst addr | src addr | type |   data    | crc |
+ * +----------+----------+----------+------+-----------+-----+
+ * </pre>
+ *
+ * type es 0x0800 para IP y 0x0806 para ARP, los únicos dos protocolos que
+ * soportamos sobre ethernet.
+ * El preamble y el crc los pone la placa de red automáticamente.
+ */
+
+/** Tamaño de dirección MAC (en bytes) */
+#define MAC_ADDR_SIZE 6
+
+/** Dirección MAC nuestra */
+extern byte mac_addr_local[ETH_MAC_SIZE];
+
+/** Dirección MAC de destino */
+extern byte mac_addr_remote[ETH_MAC_SIZE];
+
+/** Indica si el frame transporta ARP (si no transporta IP) */
+extern bool eth_frame_arp; /* FIXME: debería ser un bit manejado con ASM supongo */
+
+/**
+ * Lee la cabecera del frame ethernet.
+ *
+ * Deja en mac_addr_remote la MAC de origen y eth_frame_arp en 1 si es ARP.
+ * Si devuelve false (0) hay un error o es un frame no soportado, por lo que
+ * hay que descartarlo.
+ */
+bool eth_read_frame_header();
+
+/**
+ * Escribe la cabecera del frame ethernet.
+ *
+ * Pone como destino a mac_addr_remote, como origen a mac_addr_local y como
+ * tipo ARP si eth_frame_arp está en 1 (si no el tipo es IP).
+ */
+void eth_write_frame_header();
+
+#endif /* _ETH_H_ */
diff --git a/src/c/ip.c b/src/c/ip.c
new file mode 100644 (file)
index 0000000..44dd1ac
--- /dev/null
@@ -0,0 +1,105 @@
+#include "ip.h"
+
+/** protocolos soportados */
+enum { ICMP = 0x01, UDP = 0x11 };
+
+extern byte ip_addr_local[IP_ADDR_SIZE];
+
+extern byte ip_addr_remote[IP_ADDR_SIZE];
+
+byte ip_packet_len;
+
+bool ip_proto_icmp;
+
+bool ip_read_packet_header()
+{
+       /* variable para utilitaria (iterar y/o buffer) */
+       byte c;
+       /* versión y tamaño de cabecera vienen en el 1er byte */
+       c = net_getb();
+       /* sólo soportamos versión 4 */
+       if ((c >> 4) != 4)
+               return false; /* drop */
+       /* tamaño de cabecera */
+       if ((c & 0x0F) != 5) /* no aceptamos opciones raras =) */
+               return false; /* drop */
+       /* ignoramos el TOS */
+       net_getb();
+       /* obtenemos tamaño del paquete */
+       if (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 */
+       /* 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)
+               return false; /* drop */
+       /* no le damos bola al TTL (no le vamos a hacer lío si ya llegó hasta
+        * acá el pobre =) */
+       net_getb();
+       /* protocolo (sólo soportamos UDP e ICMP) */
+       switch (net_getb())
+       {
+               case ICMP:
+                       ip_proto_icmp = true;
+                       break;
+               case UDP:
+                       ip_proto_icmp = false;
+                       break;
+               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 */
+       return true;
+}
+
+void ip_write_packet_header()
+{
+       /* variable para iterar */
+       byte i;
+       /* identificador del paquete IP (incrementa con cada paquete) */
+       static uint16 id = 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();
+       /* escribimos tamaño del paquete */
+       net_putb(0x00); /* nunca vamos a mandar algo de más de 255 bytes */
+       net_putb(ip_packet_len);
+       /* identificación (sirve para reensamblar paquetes) */
+       net_putw(id);
+       /* pedimos que no se fragmente */
+       net_putb(0x40); /* Don't Fragment (DF) = 1 */
+       net_putb(0x00); /* offset de fragmento = 0 */
+       /* TTL de 64 saltos porque está de moda */
+       net_putb(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 */
+       /* ponemos como dirección IP de origen la nuestra */
+       for (i = 0; i < IP_ADDR_SIZE; ++i)
+               net_putb(ip_addr_local[i]);
+       /* IP de destino, la remota */
+       for (i = 0; i < IP_ADDR_SIZE; ++i)
+               net_putb(ip_addr_remote[i]);
+}
+
diff --git a/src/c/ip.h b/src/c/ip.h
new file mode 100644 (file)
index 0000000..ec3a892
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef _IP_H_
+#define _IP_H_
+
+#include "types.h"
+#include "net.h"
+
+/** @file
+ * Paquete IP.
+ *
+ *  0                   1                   2                   3   
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |Version|  IHL  |Type of Service|          Total Length         |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |         Identification        |Flags|      Fragment Offset    |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |  Time to Live |    Protocol   |         Header Checksum       |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                       Source Address                          |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                    Destination Address                        |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                    Options                    |    Padding    |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                             Data                              |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 
+ * Nosotros sólo implementamos la versión 4, sin opciones, con tamaño de paquete
+ * como máximo de 255 bytes, sin fragmentación y sólo los protocolos UDP e ICMP
+ * (este último sólo para responder al ping). Todos los paquetes que no cumplan
+ * con estas restricciones son descartados.
+ */
+
+/** Tamaño de dirección IP (en bytes) */
+#define IP_ADDR_SIZE 4
+
+/** Dirección IP nuestra */
+extern byte ip_addr_local[IP_ADDR_SIZE];
+
+/** Dirección IP de destino */
+extern byte ip_addr_remote[IP_ADDR_SIZE];
+
+/** Tamaño del paquete IP */
+extern byte ip_packet_len;
+
+/** Indica si el paquete es ICMP (si no es UDP) */
+bool ip_proto_icmp;
+
+/** Lee la cabecera del paquete IP.
+ *
+ * Deja en ip_addr_remote la ip de origen.
+ * Si devuelve false (0) es que hubo un error o es un paquete no soportado, por
+ * lo que hay que descartarlo.
+ */
+bool ip_read_packet_header();
+
+/** Escribe la cabecera del paquete IP.
+ *
+ * Pone como destino a ip_addr_remote, como origen a ip_addr_local, el protocolo
+ * lo especifica según ip_proto_icmp y como tamaño pone ip_packet_len.
+ */
+void ip_write_packet_header();
+
+#endif /* _IP_H_ */
diff --git a/src/c/net.h b/src/c/net.h
new file mode 100644 (file)
index 0000000..15bed4f
--- /dev/null
@@ -0,0 +1,14 @@
+#include "net.h"
+
+uint16 net_getw()
+{
+       byte b = net_getb();
+       return (b << 8) + net_getb();
+}
+       
+void net_putw(uint16 w)
+{
+       net_putb(w >> 8); /* parte alta */;
+       net_putb(w); /* parte baja */;
+}
+
diff --git a/src/c/types.h b/src/c/types.h
new file mode 100644 (file)
index 0000000..db65dd0
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef _TYPES_H_
+#define _TYPES_H_
+
+/** valores posibles de un booleano */
+enum { false = 0, true = 1 };
+
+#if 1 /* i386 */
+
+/** booleano */
+typedef unsigned char bool;
+
+/** entero sin signo de 8 bits */
+typedef unsigned char byte;
+
+/** entero sin signo de 16 bits */
+typedef unsigned short uint16;
+
+#endif
+
+#if 0 /* 8051 */
+
+/** booleano */
+typedef unsigned char bool;
+
+/** entero sin signo de 8 bits */
+typedef unsigned char byte;
+
+/** entero sin signo de 16 bits */
+typedef unsigned int uint16;
+
+#endif
+
+#endif /* _TYPES_H_ */
diff --git a/src/c/udp.c b/src/c/udp.c
new file mode 100644 (file)
index 0000000..1c4189e
--- /dev/null
@@ -0,0 +1,38 @@
+#include "ip.h"
+
+extern uint16 udp_port_local;
+
+extern uint16 udp_port_remote;
+
+extern byte udp_dgram_len;
+
+bool udp_read_dgram_header()
+{
+       /* puerto origen */
+       udp_port_remote = net_getw();
+       /* sólo aceptamos datagramas a nuestro puerto */
+       if (net_getw() != udp_port_local)
+               return false; /* drop */
+       /* tamaño del datagrama */
+       if (net_getb()) /* no soportamos más de 255 bytes */
+               return false; /* drop */
+       udp_dgram_len = net_getb();
+       /* descartamos checksum */
+       net_getw();
+       return true;
+}
+
+void udp_write_dgram_header()
+{
+       /* puerto origen */
+       net_putw(udp_port_local);
+       /* puerto destino */
+       net_putw(udp_port_remote);
+       /* tamaño del datagrama */
+       net_putb(0x00); /* parte alta en 0 porque no soportamos más de 255 */
+       net_putb(udp_dgram_len);
+       /* indicamos que no se usa checksum */
+       net_putw(0x0000);
+       return true;
+}
+
diff --git a/src/c/udp.h b/src/c/udp.h
new file mode 100644 (file)
index 0000000..5e2d727
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _UDP_H_
+#define _UDP_H_
+
+#include "types.h"
+#include "net.h"
+
+/** @file
+ * Datagrama UDP.
+ *
+ *  0      7 8     15 16    23 24    31  
+ * +--------+--------+--------+--------+ 
+ * |     Source      |   Destination   | 
+ * |      Port       |      Port       | 
+ * +--------+--------+--------+--------+ 
+ * |                 |                 | 
+ * |     Length      |    Checksum     | 
+ * +--------+--------+--------+--------+ 
+ * |                                     
+ * |          data octets ...            
+ * +---------------- ...                 
+ *
+ * Aceptamos sólo datagramas UDP que vayan a el puerto de nuestra aplicación y
+ * cuyo tamaño sea menor a 255. El resto es descartado.
+ * El Length es tanto de la cabecera como datos, por lo tanto el tamaño mínimo
+ * es 8. El checksum no se calcula ni se verifica, ya que sabemos que la capa
+ * inferior (ethernet) tiene verificación de errores de los datos.
+ */
+
+/** Puerto UDP nuestro */
+extern uint16 udp_port_local;
+
+/** Puerto UDP de destino */
+extern uint16 udp_port_remote;
+
+/** Tamaño del datagrama UDP */
+extern byte udp_dgram_len;
+
+/** Lee la cabecera del datagrama UDP.
+ *
+ * Deja en udp_port_remote el puerto de origen.
+ * Si devuelve false (0) es que hubo un error o es un datagrama no soportado,
+ * por lo que hay que descartarlo.
+ */
+bool udp_read_dgram_header();
+
+/** Escribe la cabecera del datagrama UDP.
+ *
+ * Pone como puerto destino a udp_port_remote, como origen udp_port_local y como
+ * tamaño a udp_dgram_len (en la parte baja y 0 en la parte alta).
+ */
+void udp_write_dgram_header();
+
+#endif /* _UDP_H_ */