#include <TunOutDevice.h>
WARNING: This does ONLY work with the combination IPv4|UDP|OverlayMessage
Public Member Functions | |
Module_Class_Members (TunOutDevice, cSimpleModule, 0) | |
virtual int | numInitStages () const |
virtual void | initialize (int stage) |
Initialization of the module. | |
virtual void | handleMessage (cMessage *msg) |
The "main loop". | |
Protected Member Functions | |
InterfaceEntry * | registerInterface () |
Register the interface in the interface table of the parent. | |
void | transmitToTun (cMessage *msg) |
Send a message to the tun device. | |
void | updateDisplayString () |
virtual char * | encapsulate (cMessage *msg, unsigned int *length) |
Converts an IP datagram to a data block for sending it to the tun device. | |
virtual cMessage * | decapsulate (char *buf) |
Parses data received from the tun device and converts it into a cMessage. | |
Protected Attributes | |
InterfaceEntry * | interfaceEntry |
unsigned int | mtu |
long | numSent |
long | numSendError |
long | numRcvdOK |
long | numRcvError |
cMessage * | packetNotification |
cTunOutScheduler::PacketBuffer | packetBuffer |
cTunOutScheduler * | scheduler |
PacketParser * | parser |
cMessage * TunOutDevice::decapsulate | ( | char * | buf | ) | [protected, virtual] |
Parses data received from the tun device and converts it into a cMessage.
buf | A pointer to the data to be parsed |
00228 { 00229 // Message starts with IP header 00230 iphdr* ip_buf = (iphdr*) buf; 00231 udphdr* udp_buf; 00232 IPDatagram* IP = new IPDatagram; 00233 UDPPacket* UDP = new UDPPacket; 00234 cMessage* payload = 0; 00235 unsigned int payloadLen, datagramlen; 00236 unsigned int packetlen = ntohs(ip_buf->tot_len); 00237 00238 // Parsing of IP header, sanity checks 00239 if ( packetlen > mtu ) { 00240 ev << "TunOutDevice: Dropping bogus packet, length = " << packetlen << " but mtu = " << mtu <<".\n"; 00241 goto parse_error; 00242 } 00243 if ( ip_buf->version != 4 ) { 00244 ev << "TunOutDevice: Dropping Packet: Packet is not IPv4.\n"; 00245 goto parse_error; 00246 } 00247 if ( ntohs(ip_buf->frag_off) & 0xBFFF ) { // mask DF bit 00248 ev << "TunOutDevice: Dropping Packet: Can't handle fragmented packets.\n"; 00249 goto parse_error; 00250 } 00251 if ( ip_buf->protocol != IPPROTO_UDP ) { // FIXME: allow ICMP packets 00252 ev << "TunOutDevice: Dropping Packet: Packet is not UDP.\n"; 00253 goto parse_error; 00254 } 00255 IP->setSrcAddress( IPAddress( ntohl(ip_buf->saddr) )); 00256 IP->setDestAddress( IPAddress( ntohl(ip_buf->daddr) )); 00257 IP->setTransportProtocol( ip_buf->protocol ); 00258 IP->setTimeToLive( ip_buf->ttl ); 00259 IP->setIdentification( ntohs(ip_buf->id) ); 00260 IP->setMoreFragments( false ); 00261 IP->setDontFragment( true ); 00262 IP->setFragmentOffset( 0 ); 00263 IP->setDiffServCodePoint( ip_buf->tos ); 00264 IP->setLength( ip_buf->ihl*32 ); 00265 // FIXME: check IP and UDP checksum... 00266 00267 // Parse UDP header, sanity checks 00268 udp_buf = (udphdr*)( ((uint32_t *)ip_buf) + ip_buf->ihl ); 00269 datagramlen = ntohs(udp_buf->len); 00270 if ( (datagramlen != packetlen - ip_buf->ihl*4) ) { 00271 ev << "TunOutDevice: Dropping Packet: Bogus UDP datagram length: len = " << datagramlen << " packetlen = " << packetlen << " ihl*4 " << ip_buf->ihl*4 << ".\n"; 00272 goto parse_error; 00273 } 00274 UDP->setSourcePort( ntohs( udp_buf->source )); 00275 UDP->setDestinationPort( ntohs( udp_buf->dest )); 00276 UDP->setByteLength( sizeof( struct udphdr ) ); 00277 00278 // parse payload 00279 payloadLen = datagramlen - sizeof( struct udphdr ); 00280 payload = parser->decapsulatePayload( ((char*) udp_buf) + sizeof( struct udphdr ), payloadLen ); 00281 if (!payload) { 00282 ev << "TunOutDevice: Parsing of Payload failed, dropping packet.\n"; 00283 goto parse_error; 00284 } 00285 // encapsulate messages 00286 UDP->encapsulate( payload ); 00287 IP->encapsulate( UDP ); 00288 00289 delete buf; 00290 return IP; 00291 00292 // In case the parsing of the packet failed, free allocated memory 00293 parse_error: 00294 delete buf; 00295 delete IP; 00296 delete UDP; 00297 return NULL; 00298 }
char * TunOutDevice::encapsulate | ( | cMessage * | msg, | |
unsigned int * | length | |||
) | [protected, virtual] |
Converts an IP datagram to a data block for sending it to the tun device.
msg | A pointer to the message to be converted | |
length | A pointer to an int that will hold the length of the converted data |
00146 { 00147 struct udppseudohdr { 00148 uint32_t saddr; 00149 uint32_t daddr; 00150 uint8_t zero; 00151 uint8_t protocol; 00152 uint16_t lenght; 00153 } 00154 * pseudohdr; 00155 00156 unsigned int payloadlen; 00157 static unsigned int iplen = 20; // we don't generate IP options 00158 static unsigned int udplen = 8; 00159 00160 IPDatagram* IP = check_and_cast<IPDatagram*>(msg); 00161 // FIXME: Check for ICMP-Messages 00162 UDPPacket* UDP = check_and_cast<UDPPacket*>(IP->decapsulate()); 00163 cMessage* payloadMsg = UDP->decapsulate(); 00164 00165 // parse payload 00166 char* payload = parser->encapsulatePayload(payloadMsg, &payloadlen); 00167 if (!payload ) 00168 return NULL; 00169 00170 *length = payloadlen + iplen + udplen; 00171 if( *length > mtu ) { 00172 EV << "TunOutDevice::encapsulate: Error: Packet too big! Size = " << *length << " MTU = " << mtu << "\n"; 00173 return NULL; 00174 } 00175 00176 char* buf = new char[*length]; 00177 00178 // We use the buffer to build an ip packet. 00179 // To minimise unnecessary copying, we start with the payload 00180 // and write it to the end of the buffer 00181 memcpy( (buf + iplen + udplen), payload, payloadlen); 00182 00183 // write udp header in front of the payload 00184 udphdr* udp_buf = (udphdr*) (buf + iplen); 00185 udp_buf->source = htons(UDP->sourcePort()); 00186 udp_buf->dest = htons(UDP->destinationPort()); 00187 udp_buf->len = htons(udplen + payloadlen); 00188 udp_buf->check = 0; 00189 00190 // Write udp pseudoheader in from of udp header 00191 // this will be overwritten by ip header 00192 pseudohdr = (udppseudohdr*) (buf + iplen - sizeof(struct udppseudohdr)); 00193 uint32_t saddr = htonl(IP->srcAddress().getInt()); 00194 uint32_t daddr = htonl(IP->destAddress().getInt()); 00195 pseudohdr->saddr = saddr; 00196 pseudohdr->daddr = daddr; 00197 pseudohdr->zero = 0; 00198 pseudohdr->protocol = IPPROTO_UDP; 00199 pseudohdr->lenght = udp_buf->len; 00200 00201 // compute UDP checksum 00202 udp_buf->check = cksum((uint16_t*) pseudohdr, sizeof(struct udppseudohdr) + udplen + payloadlen); 00203 00204 // write ip header to begin of buffer 00205 iphdr* ip_buf = (iphdr*) buf; 00206 ip_buf->version = 4; // IPv4 00207 ip_buf->ihl = iplen / 4; 00208 ip_buf->tos = IP->diffServCodePoint(); 00209 ip_buf->tot_len = htons(*length); 00210 ip_buf->id = htons(IP->identification()); 00211 ip_buf->frag_off = htons(IP_DF); // DF, no fragments 00212 ip_buf->ttl = IP->timeToLive(); 00213 ip_buf->protocol = IPPROTO_UDP; 00214 ip_buf->saddr = saddr; 00215 ip_buf->daddr = daddr; 00216 ip_buf->check = 0; 00217 ip_buf->check = cksum((uint16_t*) ip_buf, iplen); 00218 00219 delete IP; 00220 delete UDP; 00221 delete payloadMsg; 00222 delete payload; 00223 00224 return buf; 00225 }
void TunOutDevice::handleMessage | ( | cMessage * | msg | ) | [virtual] |
The "main loop".
Every message that is received or send is handled by this method
00093 { 00094 // Packet from the real world... 00095 if (msg==packetNotification) { 00096 EV << "TunOutDevice: Message from outside. Queue length = " << packetBuffer.size() << ".\n"; 00097 while( packetBuffer.size() > 0 ) { 00098 // get packet from buffer and parse it 00099 char* buf = *(packetBuffer.begin()); 00100 packetBuffer.pop_front(); 00101 cMessage *parsedPacket = decapsulate(buf); 00102 if (parsedPacket) { 00103 numRcvdOK++; 00104 #ifndef _MAX_SPEED 00105 00106 send(parsedPacket,"netwOut"); 00107 #else 00108 00109 send(parsedPacket, gateIndexNetwOut); 00110 #endif 00111 00112 } else { 00113 numRcvError++; 00114 } 00115 00116 } 00117 } else // arrived on gate "netwIn" 00118 { 00119 // Packet from inside, send to real word 00120 #ifndef _MAX_SPEED 00121 EV << "Received " << msg << " for transmission\n"; // ib: speed hack 00122 #endif 00123 00124 transmitToTun(msg); 00125 } 00126 00127 if (ev.isGUI()) 00128 updateDisplayString(); 00129 00130 }
void TunOutDevice::initialize | ( | int | stage | ) | [virtual] |
Initialization of the module.
Registers the device at the scheduler and searches for the appropriate payload-parser Will be called automatically at startup
00016 { 00017 error("The TunOut underlay doesn't work in this version (work in progress)!"); 00018 00019 if (stage==3) { 00020 // update display string when addresses have been autoconfigured etc. 00021 updateDisplayString(); 00022 return; 00023 } 00024 00025 // all initialization is done in the first stage 00026 if (stage!=0) 00027 return; 00028 00029 interfaceEntry = NULL; 00030 packetNotification = new cMessage("packetNotification"); 00031 mtu = par("mtu"); 00032 00033 scheduler = check_and_cast<cTunOutScheduler *>(simulation.scheduler()); 00034 scheduler->setInterfaceModule(this, packetNotification, &packetBuffer, mtu); 00035 00036 parser = check_and_cast<PacketParser*>(parentModule()->submodule("packetParser")); 00037 numSent = numRcvdOK = numRcvError = numSendError = 0; 00038 WATCH(numSent); 00039 WATCH(numRcvdOK); 00040 WATCH(numRcvError); 00041 WATCH(numSendError); 00042 00043 #ifdef _MAX_SPEED 00044 00045 gateIndexNetwOut = gate("netwOut")->id(); 00046 #endif 00047 00048 // register our interface entry in RoutingTable 00049 interfaceEntry = registerInterface(); 00050 00051 }
TunOutDevice::Module_Class_Members | ( | TunOutDevice | , | |
cSimpleModule | , | |||
0 | ||||
) |
InterfaceEntry * TunOutDevice::registerInterface | ( | ) | [protected] |
Register the interface in the interface table of the parent.
00054 { 00055 InterfaceEntry *e = new InterfaceEntry(); 00056 00057 // interface name: our module name without special characters ([]) 00058 char *interfaceName = new char[strlen(parentModule()->fullName())+1]; 00059 char *d=interfaceName; 00060 for (const char *s=parentModule()->fullName(); *s; s++) 00061 if (isalnum(*s)) 00062 *d++ = *s; 00063 *d = '\0'; 00064 00065 e->setName(interfaceName); 00066 delete [] interfaceName; 00067 00068 // port: index of gate where our "netwIn" is connected (in IP) 00069 int outputPort = /*parentModule()->*/gate("netwIn")->fromGate()->index(); 00070 e->setNodeOutputGateId(outputPort); 00071 00072 // generate a link-layer address to be used as interface token for IPv6 00073 InterfaceToken token(0, simulation.getUniqueNumber(), 64); 00074 e->setInterfaceToken(token); 00075 00076 // MTU: typical values are 576 (Internet de facto), 1500 (Ethernet-friendly), 00077 // 4000 (on some point-to-point links), 4470 (Cisco routers default, FDDI compatible) 00078 e->setMtu(mtu); 00079 00080 // capabilities 00081 e->setMulticast(true); 00082 e->setPointToPoint(true); 00083 00084 // add 00085 InterfaceTable *ift = InterfaceTableAccess().get(); 00086 ift->addInterface(e, NULL); 00087 00088 return e; 00089 }
void TunOutDevice::transmitToTun | ( | cMessage * | msg | ) | [protected] |
Send a message to the tun device.
msg | A pointer to the message to be send |
00133 { 00134 unsigned int length; 00135 char* buf = encapsulate(msg, &length); 00136 if( buf ) { 00137 numSent++; 00138 scheduler->sendBytes( buf, length ); 00139 } else { 00140 numSendError++; 00141 } 00142 delete buf; 00143 }
void TunOutDevice::updateDisplayString | ( | ) | [protected] |
00301 { 00302 char buf[80]; 00303 if (ev.disabled()) { 00304 // speed up things 00305 displayString().setTagArg("t",0,""); 00306 } 00307 sprintf(buf, "rcv:%ld snt:%ld", numRcvdOK, numSent); 00308 00309 if (numRcvError>0) 00310 sprintf(buf+strlen(buf), "\nerrin:%ld errout:%ld", numRcvError, numSendError); 00311 00312 displayString().setTagArg("t",0,buf); 00313 }
InterfaceEntry* TunOutDevice::interfaceEntry [protected] |
unsigned int TunOutDevice::mtu [protected] |
long TunOutDevice::numRcvdOK [protected] |
long TunOutDevice::numRcvError [protected] |
long TunOutDevice::numSendError [protected] |
long TunOutDevice::numSent [protected] |
cMessage* TunOutDevice::packetNotification [protected] |
PacketParser* TunOutDevice::parser [protected] |
cTunOutScheduler* TunOutDevice::scheduler [protected] |