]> git.llucax.com Git - z.facultad/66.09/etherled.git/blob - src/udp.c
Implementado el checksum de UDP, tanto para paquetes recibidos como para
[z.facultad/66.09/etherled.git] / src / udp.c
1 // vim: set et sw=4 sts=4 :     
2
3 #include "debug.h"
4 #include "netdev.h"
5 #include "ip.h"
6 #include "udp.h"
7
8 uint16 udp_port_local;
9
10 uint16 udp_port_remote;
11
12 byte udp_dgram_len;
13
14 /* para calcular checksum */
15 static uint16 checksum;
16 static byte byte_count;
17 static byte last_byte;
18
19 /* agrega un word al checksum calculado */
20 static void sum(uint16 w)
21 {
22     checksum += w;
23     if (checksum < w) /* corrección de carry (hubo OV) */
24         ++checksum;
25 }
26
27 bool udp_read_dgram_header()
28 {
29     byte tmp;
30     bit ok = true;
31     netdev_read_start(UDP_HEADER_SIZE);
32     /* reseteamos checksum */
33     checksum = 0;
34     byte_count = 0;
35     /* el UDP tiene un checksum que incluye parte de la cabecera IP */
36     /* ip de origen */
37     sum(WORD(ip_addr_remote[0], ip_addr_remote[1]));
38     sum(WORD(ip_addr_remote[2], ip_addr_remote[3]));
39     /* ip de destino */
40     sum(WORD(ip_addr_local[0], ip_addr_local[1]));
41     sum(WORD(ip_addr_local[2], ip_addr_local[3]));
42     /* protocolo expresado en 16 bits (0x11 es UDP) */
43     sum(0x0011);
44     /* tamaño del paquete UDP (sin las cabeceras que son 20 bytes) */
45     sum(ip_packet_len - 20);
46     /* de ahora en más todos los datos del checksum corresponden a UDP */
47     /* puerto origen (remoto) */
48     udp_port_remote = netdev_read_word();
49     /* agregamos puerto de origen al checksum */
50     sum(udp_port_remote);
51     /* sólo aceptamos datagramas a nuestro puerto */
52     if (netdev_read_word() != udp_port_local)
53         ok = false; /* drop */
54     /* agregamos puerto de destino al checksum */
55     sum(udp_port_local);
56     /* tamaño del datagrama */
57     if (tmp = netdev_read_byte()) /* no soportamos más de 255 bytes */
58         ok = false; /* drop */
59     udp_dgram_len = netdev_read_byte(); /* parte baja */
60     if (udp_dgram_len < 8) /* no puede ser más chico que sus cabeceras */
61         ok = false; /* drop */
62     /* agregamos tamaño al checksum */
63     sum(WORD(tmp, udp_dgram_len));
64     /* agregamos checksum al checksum */
65     sum(netdev_read_word());
66     /* falta agregar el cuerpo del mensaje para verificar la suma
67      * esto debe hacerlo el protocolo que sigue para poder seguir obteniendo
68      * los datos de la placa de red byte a byte */
69     netdev_read_end();
70     return true;
71 }
72
73 byte udp_read_byte()
74 {
75     byte b;
76     if (byte_count % 2) // impar, tengo 2, sumo
77     {
78         b = netdev_read_byte();
79         sum(WORD(last_byte, b));
80     }
81     else // par, guardo para sumar cuando tenga 2
82     {
83         b = netdev_read_byte();
84         last_byte = b;
85     }
86     ++byte_count;
87     return b;
88 }
89
90 bool udp_checksum_ok()
91 {
92     // Verifico si falta sumar algo (UDP debe sumar de a un word)
93     if (byte_count == (udp_dgram_len - UDP_HEADER_SIZE))
94         sum(WORD(last_byte, 0x00)); // Relleno el byte que falta con 0x00
95     return !(uint16)~checksum;
96 }
97
98 void udp_write_dgram_header()
99 {
100     netdev_write_start(UDP_HEADER_SIZE);
101     /* reseteamos checksum */
102     checksum = 0;
103     byte_count = 0;
104     /* el UDP tiene un checksum que incluye parte de la cabecera IP */
105     /* ip de origen */
106     sum(WORD(ip_addr_remote[0], ip_addr_remote[1]));
107     sum(WORD(ip_addr_remote[2], ip_addr_remote[3]));
108     /* ip de destino */
109     sum(WORD(ip_addr_local[0], ip_addr_local[1]));
110     sum(WORD(ip_addr_local[2], ip_addr_local[3]));
111     /* protocolo expresado en 16 bits (0x11 es UDP) */
112     sum(0x0011);
113     /* tamaño del paquete UDP (IP sin las cabeceras, que son 20 bytes) */
114     sum(ip_packet_len - 20); // FIXME
115     /* puerto origen */
116     netdev_write_word(udp_port_local);
117     sum(udp_port_local);
118     /* puerto destino */
119     netdev_write_word(udp_port_remote);
120     sum(udp_port_remote);
121     /* tamaño del datagrama */
122     netdev_write_byte(0x00); /* parte alta en 0 porque no soportamos más de 255 */
123     netdev_write_byte(udp_dgram_len);
124     sum(WORD(0x00, udp_dgram_len));
125     /* indicamos que no se usa checksum */
126     netdev_write_word(0x0000);
127     sum(0x0000);
128     netdev_write_end();
129 }
130
131 void udp_write_byte(byte b)
132 {
133     if (byte_count % 2) // impar, tengo 2, sumo
134     {
135         netdev_write_byte(b);
136         sum(WORD(last_byte, b));
137     }
138     else // par, guardo para sumar cuando tenga 2
139     {
140         netdev_write_byte(b);
141         last_byte = b;
142     }
143     ++byte_count;
144 }
145
146 void udp_write_checksum(byte offset)
147 {
148     // Verifico si falta sumar algo (UDP debe sumar de a un word)
149     if (byte_count == (udp_dgram_len - UDP_HEADER_SIZE))
150         sum(WORD(last_byte, 0x00)); // Relleno el byte que falta con 0x00
151     // Escribo checksum en el buffer de la placa de red
152     netdev_write_start_at(offset + 6, 2); // 6 bytes de offset hasta el checksum
153     netdev_write_word((uint16)~checksum); // Guardo checksum
154     netdev_write_end();
155     return;
156 }
157