1 // vim: set et sw=4 sts=4 :
7 /** protocolos soportados */
8 enum { ICMP = 0x01, UDP = 0x11 };
10 byte ip_addr_local[IP_ADDR_SIZE];
12 byte ip_addr_remote[IP_ADDR_SIZE];
18 /* para calcular checksum */
19 static uint16 checksum;
21 /* agrega un word al checksum calculado */
22 static void sum(uint16 w)
25 if (checksum < w) /* corrección de carry (hubo OV) */
29 bool ip_read_packet_header()
31 /* variables utilitarias (iterar y/o buffer) */
34 netdev_read_start(IP_HEADER_SIZE);
35 /* reseteamos checksum */
37 /* versión y tamaño de cabecera vienen en el 1er byte */
38 h = netdev_read_byte();
39 /* sólo soportamos versión 4 */
42 /* tamaño de cabecera */
43 if ((h & 0x0F) != 5) /* no aceptamos opciones raras =) */
45 /* ignoramos el TOS y vamos calculando checksum */
46 sum(WORD(h, netdev_read_byte()));
47 /* obtenemos tamaño del paquete */
48 if (h = netdev_read_byte()) /* tiene más de 255 bytes (no lo soportamos) */
50 ip_packet_len = netdev_read_byte(); /* hasta 255 bytes tienen los nuestros */
51 /* vamos calculando checksum */
52 sum(WORD(h, ip_packet_len));
53 /* ignoramos identificación (2 bytes) y vamos calculando checksum */
54 sum(netdev_read_word());
55 /* si tiene prendido el bit de MF (More Fragments, bit 5 del byte, bit 2
56 * de los flags de la cabecera) o si tiene un offset de fragmento (bits
57 * del 4 al 0 y todos los bits del byte siguiente), dropeamos (no
58 * soportamos fragmentación) */
59 h = netdev_read_byte();
60 l = netdev_read_byte();
63 /* seguimos calculando checksum */
65 /* no le damos bola al TTL (no le vamos a hacer lío si ya llegó hasta
67 h = netdev_read_byte();
68 /* protocolo (sólo soportamos UDP e ICMP) */
69 l = netdev_read_byte();
81 /* sigo calculando checksum */
83 /* obtenemos checksum y seguimos el cálculo */
84 sum(netdev_read_word());
85 /* obtenemos IP de origen (mientras seguimos calculando el checksum) */
86 for (l = 0; l < IP_ADDR_SIZE; ++l)
88 ip_addr_remote[l] = netdev_read_byte();
90 sum(WORD(h, ip_addr_remote[l]));
92 h = ip_addr_remote[l];
94 /* vemos si el paquete es para nosotros (ningún soportar broadcast =)
95 * (mientras seguimos calculando el checksum) */
96 // TODO si soportamos DHCP hay que aceptar broadcasts!
97 for (l = 0; l < IP_ADDR_SIZE; ++l)
99 if (ip_addr_local[l] != netdev_read_byte())
102 sum(WORD(h, ip_addr_local[l]));
104 h = ip_addr_local[l];
106 /* verificamos checksum */
107 if ((uint16)~checksum)
113 void ip_write_packet_header()
115 /* variables utilitarias (iterar y/o buffer) */
117 /* identificador del paquete IP (incrementa con cada paquete) */
119 /* reseteamos checksum */
121 netdev_write_start(IP_HEADER_SIZE);
122 /* versión (4) y tamaño de cabecera (5 words de 4 bytes = 20 bytes) */
123 netdev_write_byte(h = 0x45);
124 /* TOS (0xc0 = Internetwork Control, 0x00 = normal) */
125 l = (ip_proto == IP_ICMP) ? 0xc0 : 0x00;
126 netdev_write_byte(l);
127 sum(WORD(h, l)); /* actualizamos checksum */
128 /* escribimos tamaño del paquete */
129 netdev_write_byte(h = 0x00); /* nunca vamos a mandar algo de más de 255 bytes */
130 netdev_write_byte(ip_packet_len);
131 sum(WORD(h, ip_packet_len)); /* actualizamos checksum */
132 /* identificación (sirve para reensamblar paquetes) */
133 netdev_write_word(++id);
134 sum(id); /* actualizamos checksum */
135 /* pedimos que no se fragmente */
136 netdev_write_byte(h = 0x40); /* Don't Fragment (DF) = 1 */
137 netdev_write_byte(l = 0x00); /* offset de fragmento = 0 */
138 sum(WORD(h, l)); /* actualizamos checksum */
139 /* TTL de 64 saltos porque está de moda */
140 netdev_write_byte(h = 0x40);
141 /* protocolo (sólo soportamos UDP e ICMP) */
142 l = (ip_proto == IP_ICMP) ? ICMP : UDP;
143 netdev_write_byte(l);
144 sum(WORD(h, l)); /* actualizamos checksum */
145 /* checksum: antes de poder escribir el checksum hay que terminar de
146 * calcularlo según las direcciones IP de origen y destino, así que eso
148 for (l = 0; l < IP_ADDR_SIZE; ++l) /* origen = local */
150 sum(WORD(h, ip_addr_local[l]));
152 h = ip_addr_local[l];
153 for (l = 0; l < IP_ADDR_SIZE; ++l) /* destino = remota */
155 sum(WORD(h, ip_addr_remote[l]));
157 h = ip_addr_remote[l];
158 /* ahora sí grabamos el checksum */
159 netdev_write_word(~checksum);
160 /* ahora sí, continuamos poniendo las direcciones */
161 /* ponemos como dirección IP de origen la nuestra */
162 for (l = 0; l < IP_ADDR_SIZE; ++l)
163 netdev_write_byte(ip_addr_local[l]);
164 /* IP de destino, la remota */
165 for (l = 0; l < IP_ADDR_SIZE; ++l)
166 netdev_write_byte(ip_addr_remote[l]);