1 // vim: set et sw=4 sts=4 :
6 /** protocolos soportados */
7 enum { ICMP = 0x01, UDP = 0x11 };
9 byte ip_addr_local[IP_ADDR_SIZE];
11 byte ip_addr_remote[IP_ADDR_SIZE];
17 /* para calcular checksum */
18 static uint16 checksum;
20 /* agrega un word al checksum calculado */
21 static void sum(uint16 w)
24 if (checksum < w) /* corrección de carry (hubo OV) */
28 bool ip_read_packet_header()
30 /* variables utilitarias (iterar y/o buffer) */
32 /* reseteamos checksum */
34 /* versión y tamaño de cabecera vienen en el 1er byte */
35 h = netdev_recv_byte();
36 /* sólo soportamos versión 4 */
38 return false; /* drop */
39 /* tamaño de cabecera */
40 if ((h & 0x0F) != 5) /* no aceptamos opciones raras =) */
41 return false; /* drop */
42 /* ignoramos el TOS y vamos calculando checksum */
43 sum(WORD(h, netdev_recv_byte()));
44 /* obtenemos tamaño del paquete */
45 if (h = netdev_recv_byte()) /* tiene más de 255 bytes (no lo soportamos) */
46 return false; /* drop */
47 ip_packet_len = netdev_recv_byte(); /* hasta 255 bytes tienen los nuestros */
48 /* vamos calculando checksum */
49 sum(WORD(h, ip_packet_len));
50 /* ignoramos identificación (2 bytes) y vamos calculando checksum */
51 sum(netdev_recv_word());
52 /* si tiene prendido el bit de MF (More Fragments, bit 5 del byte, bit 2
53 * de los flags de la cabecera) o si tiene un offset de fragmento (bits
54 * del 4 al 0 y todos los bits del byte siguiente), dropeamos (no
55 * soportamos fragmentación) */
56 h = netdev_recv_byte();
57 l = netdev_recv_byte();
59 return false; /* drop */
60 /* seguimos calculando checksum */
62 /* no le damos bola al TTL (no le vamos a hacer lío si ya llegó hasta
64 h = netdev_recv_byte();
65 /* protocolo (sólo soportamos UDP e ICMP) */
66 l = netdev_recv_byte();
76 return false; /* drop */
78 /* sigo calculando checksum */
80 /* obtenemos checksum y seguimos el cálculo */
81 sum(netdev_recv_word());
82 /* obtenemos IP de origen (mientras seguimos calculando el checksum) */
83 for (l = 0; l < IP_ADDR_SIZE; ++l)
85 ip_addr_remote[l] = netdev_recv_byte();
87 sum(WORD(h, ip_addr_remote[l]));
89 h = ip_addr_remote[l];
91 /* vemos si el paquete es para nosotros (ningún soportar broadcast =)
92 * (mientras seguimos calculando el checksum) */
93 // TODO si soportamos DHCP hay que aceptar broadcasts!
94 for (l = 0; l < IP_ADDR_SIZE; ++l)
96 if (ip_addr_local[l] != netdev_recv_byte())
97 return false; /* drop (no es para nosotros) */
99 sum(WORD(h, ip_addr_local[l]));
101 h = ip_addr_local[l];
103 /* verificamos checksum */
104 if ((uint16)~checksum)
105 return false; /* checksum malo, drop */
109 void ip_write_packet_header()
111 /* variables utilitarias (iterar y/o buffer) */
113 /* identificador del paquete IP (incrementa con cada paquete) */
115 /* reseteamos checksum */
117 /* versión (4) y tamaño de cabecera (5 words de 4 bytes = 20 bytes) */
118 netdev_send_byte(h = 0x45);
119 /* TOS (0xc0 = Internetwork Control, 0x00 = normal) */
120 l = (ip_proto == IP_ICMP) ? 0xc0 : 0x00;
122 sum(WORD(h, l)); /* actualizamos checksum */
123 /* escribimos tamaño del paquete */
124 netdev_send_byte(h = 0x00); /* nunca vamos a mandar algo de más de 255 bytes */
125 netdev_send_byte(ip_packet_len);
126 sum(WORD(h, ip_packet_len)); /* actualizamos checksum */
127 /* identificación (sirve para reensamblar paquetes) */
128 netdev_send_word(id);
129 sum(id); /* actualizamos checksum */
130 /* pedimos que no se fragmente */
131 netdev_send_byte(h = 0x40); /* Don't Fragment (DF) = 1 */
132 netdev_send_byte(l = 0x00); /* offset de fragmento = 0 */
133 sum(WORD(h, l)); /* actualizamos checksum */
134 /* TTL de 64 saltos porque está de moda */
135 netdev_send_byte(h = 0x40);
136 /* protocolo (sólo soportamos UDP e ICMP) */
137 l = (ip_proto == IP_ICMP) ? ICMP : UDP;
139 sum(WORD(h, l)); /* actualizamos checksum */
140 /* checksum: antes de poder escribir el checksum hay que terminar de
141 * calcularlo según las direcciones IP de origen y destino, así que eso
143 for (l = 0; l < IP_ADDR_SIZE; ++l) /* origen = local */
145 sum(WORD(h, ip_addr_local[l]));
147 h = ip_addr_local[l];
148 for (l = 0; l < IP_ADDR_SIZE; ++l) /* destino = remota */
150 sum(WORD(h, ip_addr_remote[l]));
152 h = ip_addr_remote[l];
153 /* ahora sí grabamos el checksum */
154 netdev_send_word(~checksum);
155 /* ahora sí, continuamos poniendo las direcciones */
156 /* ponemos como dirección IP de origen la nuestra */
157 for (l = 0; l < IP_ADDR_SIZE; ++l)
158 netdev_send_byte(ip_addr_local[l]);
159 /* IP de destino, la remota */
160 for (l = 0; l < IP_ADDR_SIZE; ++l)
161 netdev_send_byte(ip_addr_remote[l]);