--- /dev/null
+Enunciado extraoficial
+
+Hay que hacer 2 procesos, uno que manda y otro que recibe IP, por cada
+host/router. Todos los procesos que envian, ponen las cosas en una cola, todos
+los que reciben, sacan de esa cola. Se usa como MAC la IP, y como ID del mensaje
+de la cola (de esta manera cada proceso saca solo los "paquetes" con el ID/MAC
+que le corresponda).
+
+1) Campos en IP
+ id de paquete
+ ip origen
+ ip destino
+ checksum (0/1, de juguete)
+ tamaño del paquete completo
+ ToS
+ Don't Fragment (0/1)
+ End (0/1)
+ offset
+ TTL
+ tamaño de este fragmento
+ tipo de payload (IP / ICMP)
+ (se que faltan algunos, si tienen algo mas,
+ completen)
+
+2) Casos de descarte de paquetes
+ Error de checksum (silencioso)
+ No hay buffer para fragmento (silencioso)
+ Un host que no rutea recibe un paquete para otro host
+ (silencioso)
+ No hay ruta (icmp)
+ DF == 1 y MTU < size (icmp)
+ TTL == 0 (icmp)
+
+3) Comportamiento del protocolo
+ Debe rutear (si es un router)
+ Debe fragmentar y reensamblar
+ Debe contemplar todos los casos de descarte de
+ paquetes anteriores escribiendo en un archivo
+ los paquetes descartados según corresponda
+ (silecioso, icmp).
+
--- /dev/null
+# Makefile de ejemplo para C++
+#
+# Creado: jue abr 15 15:34:19 ART 2004
+#
+# Copyleft 2004 - Leandro Lucarella, Bajo licencia GPL [http://www.gnu.org/]
+#
+
+# CONFIGURACION
+################
+
+# Opciones para el compilador C/C++ en modo ansi.
+CFLAGS = -Wall -ansi -pedantic-errors
+
+# Para que explote lo mas posible
+#CFLAGS += -O3 -DNDEBUG
+
+# Para valgrind o debug
+CFLAGS += -ggdb -DDEBUG
+
+# Opciones para el compilador C++.
+CXXFLAGS = $(CFLAGS) -fno-inline
+
+# Opciones del enlazador.
+#LDFLAGS=
+
+# Compilador.
+CC=g++
+
+# Programas
+targets=test_send test_recv
+
+# Fuentes
+fuentes ?= $(wildcard *.cpp)
+
+
+# REGLAS
+#########
+
+.PHONY: all clean
+
+all: $(targets)
+
+test_send: test_send.o media.o
+
+test_recv: test_recv.o media.o
+
+depend:
+ makedepend $(fuentes)
+
+clean:
+ @$(RM) -fv *.o $(targets)
+
+# DO NOT DELETE
+
+media.o: media.h frame.h /usr/include/unistd.h /usr/include/features.h
+media.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+media.o: /usr/include/bits/posix_opt.h /usr/include/bits/types.h
+media.o: /usr/include/bits/wordsize.h /usr/include/bits/typesizes.h
+media.o: /usr/include/bits/confname.h /usr/include/getopt.h
+media.o: /usr/include/fcntl.h /usr/include/bits/fcntl.h
+media.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/endian.h
+media.o: /usr/include/bits/endian.h /usr/include/sys/select.h
+media.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+media.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
+media.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+media.o: /usr/include/sys/ipc.h /usr/include/bits/ipctypes.h
+media.o: /usr/include/bits/ipc.h /usr/include/sys/msg.h
+media.o: /usr/include/bits/msq.h
+test_recv.o: ethernetframe.h frame.h media.h /usr/include/unistd.h
+test_recv.o: /usr/include/features.h /usr/include/sys/cdefs.h
+test_recv.o: /usr/include/gnu/stubs.h /usr/include/bits/posix_opt.h
+test_recv.o: /usr/include/bits/types.h /usr/include/bits/wordsize.h
+test_recv.o: /usr/include/bits/typesizes.h /usr/include/bits/confname.h
+test_recv.o: /usr/include/getopt.h /usr/include/fcntl.h
+test_recv.o: /usr/include/bits/fcntl.h /usr/include/sys/types.h
+test_recv.o: /usr/include/time.h /usr/include/endian.h
+test_recv.o: /usr/include/bits/endian.h /usr/include/sys/select.h
+test_recv.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+test_recv.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
+test_recv.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+test_recv.o: /usr/include/sys/ipc.h /usr/include/bits/ipctypes.h
+test_recv.o: /usr/include/bits/ipc.h /usr/include/sys/msg.h
+test_recv.o: /usr/include/bits/msq.h dev.h
+test_send.o: ethernetframe.h frame.h media.h /usr/include/unistd.h
+test_send.o: /usr/include/features.h /usr/include/sys/cdefs.h
+test_send.o: /usr/include/gnu/stubs.h /usr/include/bits/posix_opt.h
+test_send.o: /usr/include/bits/types.h /usr/include/bits/wordsize.h
+test_send.o: /usr/include/bits/typesizes.h /usr/include/bits/confname.h
+test_send.o: /usr/include/getopt.h /usr/include/fcntl.h
+test_send.o: /usr/include/bits/fcntl.h /usr/include/sys/types.h
+test_send.o: /usr/include/time.h /usr/include/endian.h
+test_send.o: /usr/include/bits/endian.h /usr/include/sys/select.h
+test_send.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+test_send.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
+test_send.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+test_send.o: /usr/include/sys/ipc.h /usr/include/bits/ipctypes.h
+test_send.o: /usr/include/bits/ipc.h /usr/include/sys/msg.h
+test_send.o: /usr/include/bits/msq.h dev.h
--- /dev/null
+#ifndef _DEV_H_
+#define _DEV_H_
+
+#include "frame.h"
+#include "media.h"
+#include <stdexcept>
+
+/// Dispositivo de red (capa de enlace)
+struct Dev
+{
+
+ /// Dirección MAC
+ Frame::mac_type mac;
+
+ /// Medio físico
+ Media& media;
+
+ /// Constructor
+ Dev(const Frame::mac_type& mac, Media& media):
+ mac(mac), media(media)
+ {}
+
+ /// Envía un frame
+ void send(const Frame& frame) throw (std::runtime_error)
+ { media.transmit(frame); }
+
+ /// Recibe un frame
+ void recv(Frame& frame) throw (std::runtime_error)
+ { media.receive(frame); }
+
+ // Nada de andar copiando placas...
+ private:
+ Dev(const Dev&);
+ Dev& operator=(const Dev&);
+
+};
+
+#endif // _DEV_H_
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+#ifndef _ETHERNETFRAME_H_
+#define _ETHERNETFRAME_H_
+
+#include "frame.h"
+#include <string>
+#include <stdexcept>
+
+/// Frame de la capa física (en este caso es un mensaje enviado a una cola)
+template < size_t Size = 1500 >
+struct EthernetFrame: Frame
+{
+
+ // Atributos
+ mac_type _mac;
+ size_t _len;
+ char _frame[Size];
+
+ /// Constructor
+ EthernetFrame(const mac_type& mac):
+ _mac(mac)
+ {}
+
+ /// Constructor
+ EthernetFrame(const mac_type& mac, const std::string& d)
+ throw (std::logic_error): _mac(mac)
+ { data(d); }
+
+ /// Setea MAC
+ void mac(const mac_type& mac)
+ { _mac = mac; }
+
+ /// Obtiene MAC
+ mac_type mac() const
+ { return _mac; }
+
+ /// Obtiene longitud
+ size_t len() const
+ { return _len; }
+
+ /// Obtiene tamaño
+ size_t size() const
+ { return Size; }
+
+ /// Setea datos
+ void data(const std::string& d) throw (std::logic_error)
+ {
+ if (d.size() > Size)
+ throw std::logic_error("dato más grande que el frame");
+ _len = d.size();
+ memcpy(_frame, d.c_str(), _len);
+ }
+
+ /// Obtiene datos
+ std::string data() const
+ { return _frame; }
+
+};
+
+#endif // _ETHERNETFRAME_H_
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+#ifndef _FRAME_H_
+#define _FRAME_H_
+
+#include <string>
+
+/// Frame de la capa física (en este caso es un mensaje enviado a una cola)
+struct Frame
+{
+
+ // Tipos
+ typedef long mac_type;
+
+ /// Destructor
+ virtual ~Frame() {}
+
+ /// Setea MAC
+ virtual void mac(const mac_type& mac) = 0;
+
+ /// Obtiene MAC
+ virtual mac_type mac() const = 0;
+
+ /// Obtiene la longitud real del frame
+ virtual size_t len() const = 0;
+
+ /// Obtiene el tamaño máximo del frame (MTU)
+ virtual size_t size() const = 0;
+
+ /// Setea datos
+ virtual void data(const std::string& data) = 0;
+
+ /// Obtiene datos
+ virtual std::string data() const = 0;
+
+};
+
+#endif // _FRAME_H_
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+#include "media.h"
+#include <iostream>
+
+Media::Media(key_t key) throw (std::runtime_error)
+{
+ que_id = msgget(key, 0666); // Debe estar previamente creada
+ if (que_id == -1)
+ throw std::runtime_error("No se pudo crear la cola");
+}
+
+void Media::transmit(const Frame& frame)
+{
+ std::cout << "tx -> msgtype = " << *(((int*)&frame)+1) << "\n";
+ if (msgsnd(que_id, ((int*)&frame)+1, frame.size(), 0) == -1)
+ throw std::runtime_error("Error al poner en la cola");
+}
+
+void Media::receive(Frame& frame)
+{
+ std::cout << "rx -> msgtype = " << *(((int*)&frame)+1) << "\n";
+ if (msgrcv(que_id, ((int*)&frame)+1, frame.size(), frame.mac(), 0) == -1)
+ throw std::runtime_error("Error al sacar de la cola");
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+#ifndef _MEDIA_H_
+#define _MEDIA_H_
+
+#include "frame.h"
+#include <string>
+#include <stdexcept>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+
+/// Medio (o capa física + enlace),
+struct Media
+{
+
+ /// Identificador de la cola a usar
+ int que_id;
+
+ /// Constructor
+ Media(key_t key) throw (std::runtime_error);
+
+ /// Envía un frame
+ void transmit(const Frame& frame);
+
+ /// Recibe un frame
+ void receive(Frame& frame);
+
+ // Nada de andar copiando cables...
+ private:
+ Media(const Media&);
+ Media& operator=(const Media&);
+
+};
+
+#endif // _MEDIA_H_
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+
+#include "ethernetframe.h"
+#include "media.h"
+#include "dev.h"
+#include <iostream>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+
+int main()
+{
+ Media media(0xabcdef);
+ Dev dev(1234, media);
+ struct msqid_ds minfo;
+ for (msgctl(media.que_id, IPC_STAT, &minfo); minfo.msg_qnum;
+ msgctl(media.que_id, IPC_STAT, &minfo))
+ {
+ std::cout << "Quedan " << minfo.msg_qnum << " mensajes en la cola\n";
+ EthernetFrame<1500> f(1234);
+ dev.recv(f);
+ std::cout << f._mac << " " << f._len << " " << f._frame << "\n";
+ }
+ return 0;
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+
+#include "ethernetframe.h"
+#include "media.h"
+#include "dev.h"
+#include <iostream>
+#include <cassert>
+
+int main()
+{
+ int que_id = msgget(0xabcdef, IPC_CREAT | 0666);
+ assert(que_id != -1);
+ Media media(0xabcdef);
+ Dev dev(1234, media);
+ EthernetFrame<1500> f(1234, "hola mundo");
+ dev.send(f);
+ std::cout << "Enviado '" << f._frame << "' a " << f._mac << "\n";
+ return 0;
+}
+
+// vim: set et sw=4 sts=4 :