many fixes in icmp and rtl8139 driver code
[quarnos.git] / resources / net / udp.cpp
blob217b85545287fd8fbc9314c93938ccecd08153ed
1 /* Based on RFC768 */
3 #include "udp.h"
4 #include "ipv4.h"
5 #include "arch/low/general.h"
7 #include "libs/array.h"
9 using namespace net;
11 void udp::send(ipv4_addr addr, u16 dst_port, u16 src_port, const buffer &data) {
12 p<udp_packet> pkg = new udp_packet;
13 pkg->sender_port = to_be16(src_port);
14 pkg->receiver_port = to_be16(dst_port);
15 pkg->length = to_be16(data.get_size() + sizeof(udp_packet));
16 pkg->checksum = 0;
18 p<pseudo_header> ph = new pseudo_header;
19 ph->source = down.cast<ipv4>()->get_my_ip().to_be();
20 ph->destination = addr.to_be();
21 ph->zero = 0;
22 ph->protocol = 17;
23 ph->length = to_be16(sizeof(udp_packet) + data.get_size());
24 array<u16> ph_words = array<u16>::from_buffer(buffer::to_mem(ph));
26 buffer buf = buffer::to_mem(pkg);
27 buf += data;
29 array<u16> words = array<u16>::from_buffer(buf);
30 u32 sum = 0;
32 for (unsigned int i = 0; i < (sizeof(udp_packet) + data.get_size()) / 2; i++)
33 sum += words[i];
35 if (data.get_size() % 2)
36 sum += (u16)data[data.get_size() - 1];
38 for (unsigned int i = 0; i < sizeof(pseudo_header) / 2; i++)
39 sum += ph_words[i];
41 // ph.dispose();
43 sum = (sum & 0xffff) + (sum >> 16);
44 sum += (sum >> 16);
46 buf.cast<udp_packet>()->checksum = to_le16(~sum);
48 down->send_data(addr, 17, buf);
50 // pkg.dispose();
53 void udp::receive(const ipv4_addr &sender, const buffer &data) {
54 p<udp_packet> pkg = data.cast<udp_packet>();
56 for (int i = 0; i < ports.get_count(); i++)
57 if (ports[i] == from_be16(pkg->receiver_port))
58 listeners[i](sender, from_be16(pkg->sender_port), data.cut_first(sizeof(udp_packet)));
61 void udp::listen(u16 port, delegate<void, const ipv4_addr &, u16, const buffer &> listener) {
62 asm("cli\nhlt"::"a"(0xb0000f));
63 for (int i = 0; i < ports.get_count();) {
64 if (ports[i] == port) {
65 ports.remove(i);
66 listeners.remove(i);
67 } else
68 i++;
71 ports.add(port);
72 listeners.add(listener);