drop("Mal checksum", iph);
continue;
}
- // TODO forwarding (ponerlo en una cola para el proceso que manda)
+ //TODO forwarding (ponerlo en una cola para el proceso que manda)
if (iph.dst != ip)
{
drop("No es para nosotros y no hacemos forward", iph);
continue;
}
- //TODO a un buffer
- if (iph.proto != proto)
- {
- drop("No es el protocolo pedido", iph);
+ // Guarda en buffer
+ buffer[iph][iph.offset] = buf.substr(iph.header_len());
+ // Si tiene más fragmentos o es un protocolo distinto, sigo
+ if (iph.mf || (iph.proto != proto))
continue;
+ // No hay más fragmentos, reensamblamos (de ser necesario)
+ std::string data;
+ for (offsetmap_type::iterator i = buffer[iph].begin();
+ i != buffer[iph].end(); ++i)
+ {
+ //TODO chequear que los fragmentos estén todos
+ data += i->second;
}
+#ifdef DEBUG
+ log << "IPIn::recv: Paquete completo: data = '" << data << "'\n";
+#endif
+ buffer.erase(iph);
+ //TODO faltaría limpiar fragmentos viejos cada tanto (timer?)
src = iph.src;
dst = iph.dst;
- std::string data = buf.substr(iph.header_len());
return data;
}
}
#include "ipaddr.h"
#include "ipheader.h"
#include "dev.h"
-#include <iostream>
+#include <map>
#include <string>
+#include <iostream>
#include <stdexcept>
/// IP de recepción
/// Dispositivo de logging
std::ostream& log;
+ /// Buffers de recepción
+ struct BufferKey
+ {
+ uint16_t id;
+ uint32_t src, dst;
+ uint8_t proto;
+ BufferKey(const IPHeader& h):
+ id(h.id), src(h.src), dst(h.dst), proto(h.proto)
+ {}
+ bool operator< (const BufferKey& b) const
+ { return id < b.id && src < b.src && dst < b.dst && proto < b.proto; }
+ };
+ typedef std::map< uint16_t, std::string > offsetmap_type;
+ typedef std::map< BufferKey, offsetmap_type > buffer_type;
+ buffer_type buffer;
+
/// Constructor
IPIn(const IPAddr& ip, Dev& dev, std::ostream& log = std::cout);
bool df, uint8_t ttl, uint16_t id)
throw (std::runtime_error)
{
- // TODO fragmentar
- if (IPHeader::header_len() + data.size() > dev.mtu)
+ // No quieren fragmentar
+ if (df && (IPHeader::header_len() + data.size() > dev.mtu))
{
- drop("Tamaño de paquete más grande que MTU", data);
+ drop("Tamaño de paquete más grande que MTU y DF=1", data);
return false;
}
if (!src)
id = get_id();
IPHeader iph(4, IPHeader::header_len() + data.size(), id, df, 0, 0,
ttl, proto, src, dst);
- std::string buf((char*) &iph, sizeof(IPHeader));
- buf += data;
+ // Fragmenta (de ser necesario)
+ int max_payload = dev.mtu - IPHeader::header_len();
+ int cant_frag = data.size() / max_payload;
+ if (data.size() % max_payload)
+ ++cant_frag;
+ for (int i = 0; i < cant_frag; ++i)
+ {
+ IPHeader iph2 = iph;
+ if (i != (cant_frag - 1))
+ iph2.mf = 1;
+ iph2.offset += i * max_payload;
+ iph2.total_len -= i * max_payload;
+ iph2.do_checksum();
+ std::string buf((char*) &iph2, sizeof(IPHeader));
+ buf += data.substr(i * max_payload, max_payload);
#ifdef DEBUG
- log << "IPOut::send: IPHeader: " << iph << "\n";
- log << "IPOut::send: buf = " << buf << "\n";
+ log << "IPOut::send: Fragmento 0 => IPHeader: " << iph2 << "\n";
+ log << "\tbuf (" << buf.size() << ") = " << buf << "\n";
#endif
- dev.transmit(buf, dst /*TODO rutear */);
+ dev.transmit(buf, dst);
+ }
return true;
}
int que_id = msgget(DEV_DEFAULT_KEY, IPC_CREAT | 0666);
assert(que_id != -1);
IPAddr addr("10.10.10.2");
- Dev dev(addr);
+ Dev dev(addr, 25);
IPOut ipout(addr, dev);
if (ipout.send("hola mundo", 0, IPAddr("10.10.10.1")))
std::cout << "Enviado 'hola mundo' a 10.10.10.1\n";