Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Compound Members | File Members

tcptap.cc

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 1997, 1998 The Regents of the University of California.
00003  * All rights reserved.
00004  * 
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. All advertising materials mentioning features or use of this software
00014  *    must display the following acknowledgement:
00015  *      This product includes software developed by the MASH Research
00016  *      Group at the University of California, Berkeley.
00017  * 4. Neither the name of the University nor of the Research Group may be used
00018  *    to endorse or promote products derived from this software without
00019  *    specific prior written permission.
00020  * 
00021  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00022  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00024  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00025  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00026  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00027  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00028  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00031  * SUCH DAMAGE.
00032  */
00033 
00034 #ifndef lint
00035 static const char rcsid[] =
00036     "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/emulate/tcptap.cc,v 1.4 2002/09/23 23:25:05 alefiyah Exp $ (ISI)";
00037 #endif
00038 
00039 #include "tcptap.h"
00040 
00041 static class TCPTapAgentClass : public TclClass {
00042  public:
00043         TCPTapAgentClass() : TclClass("Agent/TCPTap") {}
00044         TclObject* create(int, const char*const*) {
00045                 return (new TCPTapAgent());
00046         }
00047 } class_tcptap_agent;
00048 
00049 
00050 
00051 TCPTapAgent::TCPTapAgent() {
00052     adv_window = DEFAULT_ADV_WINDOW;
00053 
00054     bzero(&extnode, sizeof(struct sockaddr_in));
00055     extnode.sin_port = DEFAULT_EXT_PORT;
00056     extnode.sin_addr.s_addr = inet_addr(DEFAULT_EXT_ADDR);
00057     extnode.sin_family = AF_INET;
00058 
00059     bzero(&nsnode, sizeof(struct sockaddr_in));
00060     nsnode.sin_port = DEFAULT_NS_PORT;
00061     nsnode.sin_addr.s_addr = inet_addr(DEFAULT_NS_ADDR);
00062     nsnode.sin_family = AF_INET;
00063     
00064     dropp = 0; 
00065 }
00066 
00067 
00068 
00069 /*
00070  * Methods to set ip addresses and port numbers from Tcl scripts.
00071  */
00072 int
00073 TCPTapAgent::command(int argc, const char*const* argv)
00074 {
00075   if (argc == 3) {
00076     if (strcmp(argv[1], "nsipaddr") == 0) {
00077       if ((nsnode.sin_addr.s_addr = inet_addr(argv[2])) 
00078           == INADDR_NONE) {
00079         printf("Error setting ns ip address");
00080         exit(1);
00081       }
00082       return (TCL_OK);
00083     }   
00084     
00085     
00086     if (strcmp(argv[1], "extipaddr") == 0) {
00087       if ((extnode.sin_addr.s_addr = inet_addr(argv[2])) 
00088           == INADDR_NONE) {
00089         printf("Error setting external ip address");
00090         exit(1);
00091       }
00092       return (TCL_OK);
00093     }
00094     
00095     if (strcmp(argv[1], "extport") == 0) {
00096       extnode.sin_port = atoi(argv[2]);
00097       return (TCL_OK);
00098     }
00099 
00100     if (strcmp(argv[1], "advertised-window") == 0) {
00101       adv_window = atoi(argv[2]);
00102       return (TCL_OK);
00103     }
00104 
00105 
00106     
00107   } /* if (argc == 3) */
00108   return (TapAgent::command(argc, argv));
00109 }
00110 
00111 
00112 
00113 unsigned short 
00114 TCPTapAgent::trans_check(unsigned char proto,
00115                          char *packet,
00116                          int length,
00117                          struct in_addr source_address,
00118                          struct in_addr dest_address)
00119 {
00120   char *pseudo_packet;
00121   unsigned short answer;
00122   
00123   pseudohdr.protocol = proto;
00124   pseudohdr.length = htons(length);
00125   pseudohdr.place_holder = 0;
00126 
00127   pseudohdr.source_address = source_address;
00128   pseudohdr.dest_address = dest_address;
00129   
00130   if((pseudo_packet = (char *) malloc(sizeof(pseudohdr) + length)) == NULL)  {
00131     perror("malloc");
00132     exit(1);
00133   }
00134   
00135   memcpy(pseudo_packet,&pseudohdr,sizeof(pseudohdr));
00136   memcpy((pseudo_packet + sizeof(pseudohdr)),
00137          packet,length);
00138   
00139   answer = (unsigned short)in_cksum((unsigned short *)pseudo_packet,
00140                                     (length + sizeof(pseudohdr)));
00141   free(pseudo_packet);
00142   return answer;
00143 }
00144 
00145 
00146 
00147 
00148 
00149 /*
00150  * Taken from the raw-sock program
00151  */
00152 unsigned short 
00153 TCPTapAgent::in_cksum(unsigned short *addr, int len)
00154 {
00155   register int sum = 0;
00156   u_short answer = 0;
00157   register u_short *w = addr;
00158   register int nleft = len;
00159   
00160   /*
00161    * Our algorithm is simple, using a 32 bit accumulator (sum), we add
00162    * sequential 16 bit words to it, and at the end, fold back all the
00163    * carry bits from the top 16 bits into the lower 16 bits.
00164    */
00165   while (nleft > 1)  {
00166     sum += *w++;
00167     nleft -= 2;
00168   }
00169   
00170   /* mop up an odd byte, if necessary */
00171   if (nleft == 1) {
00172     *(u_char *)(&answer) = *(u_char *)w ;
00173     sum += answer;
00174   }
00175   
00176   /* add back carry outs from top 16 bits to low 16 bits */
00177   sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
00178   sum += (sum >> 16);                     /* add carry */
00179   answer = ~sum;                          /* truncate to 16 bits */
00180   return(answer);
00181   
00182 }
00183 
00184 
00185 
00186 void 
00187 TCPTapAgent::ip_gen(char *packet, unsigned char protocol, 
00188             struct in_addr saddr, struct in_addr daddr,
00189             unsigned short length, unsigned char ttl)
00190 {
00191 
00192   struct ip *ipheader;
00193   
00194   ipheader = (struct ip *) packet;
00195   bzero((void *) ipheader, IP_HEADER_LEN);
00196 
00197   ipheader->ip_hl = (IP_HEADER_LEN / 4);
00198   ipheader->ip_v = IPVERSION;
00199 
00200   ipheader->ip_len = length;
00201   ipheader->ip_id = 0;
00202   ipheader->ip_ttl = ttl;
00203   ipheader->ip_p = protocol;
00204   
00205   ipheader->ip_src = saddr;
00206   ipheader->ip_dst = daddr;
00207 
00208   ipheader->ip_len = ntohs(ipheader->ip_len);
00209   ipheader->ip_off = ntohs(ipheader->ip_off);
00210 
00211   ipheader->ip_sum = (unsigned short) in_cksum((unsigned short *) ipheader,
00212                                                 sizeof(struct ip));
00213 
00214 }
00215 
00216 
00217 
00218 
00219 void
00220 TCPTapAgent::tcp_gen(char *packet, unsigned short sport, unsigned short dport, 
00221         Packet *nsp)
00222 {
00223   struct tcphdr *tcpheader;
00224 
00225   hdr_tcp* ns_tcphdr = HDR_TCP(nsp);
00226 
00227   tcpheader = (struct tcphdr *) packet;
00228   memset((char *)tcpheader, '\0', sizeof(struct tcphdr));
00229 
00230 #ifndef LINUX_TCP_HEADER
00231 
00232   tcpheader->th_sport = htons(sport);
00233   tcpheader->th_dport = htons(dport);
00234 
00235   tcpheader->th_seq = htonl(ns_tcphdr->seqno_);
00236   tcpheader->th_ack = htonl(ns_tcphdr->ackno_);
00237   
00238   tcpheader->th_off = (TCP_HEADER_LEN / 4);
00239   
00240   tcpheader->th_win = htons(adv_window);
00241 
00242   /* 
00243      Here we only propogate the "well-known" flags.
00244      If you want to add other flags, uncomment this line
00245      and comment the rest.
00246 
00247   tcpheader->th_flags = ns_tcphdr->tcp_flags_;
00248   */
00249 
00250   tcpheader->th_flags = 0;
00251   if (ns_tcphdr->tcp_flags_ & TH_FIN) 
00252     tcpheader->th_flags |= TH_FIN;
00253   if (ns_tcphdr->tcp_flags_ & TH_SYN) 
00254     tcpheader->th_flags |= TH_SYN;
00255   if (ns_tcphdr->tcp_flags_ & TH_RST) 
00256     tcpheader->th_flags |= TH_RST;
00257   if (ns_tcphdr->tcp_flags_ & TH_PUSH) 
00258     tcpheader->th_flags |= TH_PUSH;
00259   if (ns_tcphdr->tcp_flags_ & TH_ACK) 
00260     tcpheader->th_flags |= TH_ACK;
00261   if (ns_tcphdr->tcp_flags_ & TH_URG) 
00262     tcpheader->th_flags |= TH_URG;
00263 
00264 #else  /* LINUX_TCP_HEADER */
00265 
00266 #define TH_FIN  0x01
00267 #define TH_SYN  0x02
00268 #define TH_RST  0x04
00269 #define TH_PUSH 0x08
00270 #define TH_ACK  0x10
00271 #define TH_URG  0x20
00272 
00273   tcpheader->source = htons(sport);
00274   tcpheader->dest = htons(dport);
00275 
00276   tcpheader->seq = htonl(ns_tcphdr->seqno_);
00277   tcpheader->ack_seq = htonl(ns_tcphdr->ackno_);
00278   
00279   tcpheader->doff = (TCP_HEADER_LEN / 4);
00280   tcpheader->window = htons(adv_window);
00281 
00282   /* Set the appropriate flag bits */
00283  if (ns_tcphdr->tcp_flags_ & TH_FIN) 
00284     tcpheader->fin= 1;
00285   if (ns_tcphdr->tcp_flags_ & TH_SYN) 
00286     tcpheader->syn = 1;
00287   if (ns_tcphdr->tcp_flags_ & TH_RST) 
00288     tcpheader->rst =1;
00289   if (ns_tcphdr->tcp_flags_ & TH_PUSH) 
00290     tcpheader->psh = 1;
00291   if (ns_tcphdr->tcp_flags_ & TH_ACK) 
00292     tcpheader->ack = 1;
00293   if (ns_tcphdr->tcp_flags_ & TH_URG) 
00294     tcpheader->urg =1;
00295 
00296 #endif /* End of LINUX_TCP_HEADER */
00297 
00298 
00299 }
00300 
00301 void
00302 TCPTapAgent::pkt_handler(void *clientdata, Packet *p, const struct timeval &ts)
00303 {
00304   TCPTapAgent *inst = (TCPTapAgent *)clientdata;
00305   inst->processpkt(p, ts);
00306 }
00307 
00308 void
00309 TCPTapAgent::processpkt(Packet *p, const struct timeval &ts)
00310 {
00311   struct ip *ipheader;
00312   struct tcphdr *tcpheader;
00313   unsigned char *buf;
00314   
00315   /* Ip header information from the grabbed packet. */
00316   unsigned char ttl;
00317   
00318   /* Code to drop packet, if needed 
00319   dropp++;
00320   if ((dropp % 10) == 0) {
00321     fprintf(stdout,
00322             "Dropping packet number : %d\n", dropp);
00323     Packet::free(p);
00324     return ;
00325     
00326     } */
00327  
00328 
00329   ipheader = (struct ip *) p->accessdata();
00330   if (in_cksum((unsigned short *) ipheader, (ipheader->ip_hl * 4))) {
00331     fprintf(stderr,
00332             "TCPTapAgent(%s): packet received with invalid IP checksum.\n",
00333             name());
00334     drop(p);
00335     return;
00336   }
00337 
00338   ttl = ipheader->ip_ttl;
00339   if (!(--ttl)) {
00340     fprintf(stderr, 
00341             "TCPTapAgent(%s): packet received with ttl zero.\n",
00342             name());
00343     drop(p);
00344     return;
00345     
00346   }    
00347 
00348   buf = p->accessdata(); 
00349   tcpheader = (struct tcphdr *) (buf + (ipheader->ip_hl * 4));
00350   
00351   Packet *nspacket = allocpkt();
00352 
00353   hdr_ip *ns_iphdr = HDR_IP(nspacket);
00354   ns_iphdr->ttl() = ttl;
00355 
00356   hdr_tcp *ns_tcphdr = HDR_TCP(nspacket);       
00357 #ifndef LINUX_TCP_HEADER 
00358 
00359   ns_tcphdr->seqno() = ntohl(tcpheader->th_seq);
00360   ns_tcphdr->ackno() = ntohl(tcpheader->th_ack);
00361   ns_tcphdr->hlen() = (ipheader->ip_hl + tcpheader->th_off) * 4;
00362   ns_tcphdr->ts() = Scheduler::instance().clock();
00363   ns_tcphdr->reason() |= REASON_UNKNOWN;
00364 
00365   /* 
00366      Here we only propogate the "well-known" flags.
00367      If you want to add other flags, uncomment this line
00368      and comment the rest.
00369 
00370      ns_tcphdr->flags() = tcpheader->th_flags;
00371   */
00372 
00373   ns_tcphdr->flags() = 0;
00374   if (tcpheader->th_flags & TH_FIN)
00375     ns_tcphdr->flags() |= TH_FIN;
00376   if (tcpheader->th_flags & TH_SYN) 
00377         ns_tcphdr->flags() |= TH_SYN;
00378   if (tcpheader->th_flags & TH_RST) 
00379         ns_tcphdr->flags() |= TH_RST;
00380   if (tcpheader->th_flags & TH_PUSH) 
00381         ns_tcphdr->flags() |= TH_PUSH;
00382   if (tcpheader->th_flags & TH_ACK) 
00383         ns_tcphdr->flags() |= TH_ACK;
00384   if (tcpheader->th_flags & TH_URG) 
00385         ns_tcphdr->flags() |= TH_URG;
00386 
00387 #else /* LINUX_TCP_HEADER */
00388  
00389   ns_tcphdr->seqno() = ntohl(tcpheader->seq);
00390   ns_tcphdr->ackno() = ntohl(tcpheader->ack);
00391   ns_tcphdr->hlen() = (ipheader->ip_hl + tcpheader->doff) * 4;
00392   ns_tcphdr->ts() = Scheduler::instance().clock();
00393   ns_tcphdr->reason() |= REASON_UNKNOWN;
00394 
00395   /* 
00396      Here we only propogate the "well-known" flags.
00397      If you want to add other flags, uncomment this line
00398      and comment the rest.
00399 
00400      ns_tcphdr->flags() = tcpheader->th_flags;
00401   */
00402 
00403 #define TH_FIN  0x01
00404 #define TH_SYN  0x02
00405 #define TH_RST  0x04
00406 #define TH_PUSH 0x08
00407 #define TH_ACK  0x10
00408 #define TH_URG  0x20
00409 
00410   ns_tcphdr->flags() = 0;
00411 
00412   if (tcpheader->fin == 1 )
00413     ns_tcphdr->flags() |= TH_FIN;
00414   if (tcpheader->syn == 1 ) 
00415         ns_tcphdr->flags() |= TH_SYN;
00416   if (tcpheader->rst == 1 ) 
00417         ns_tcphdr->flags() |= TH_RST;
00418   if (tcpheader->psh == 1) 
00419         ns_tcphdr->flags() |= TH_PUSH;
00420   if (tcpheader->ack == 1) 
00421         ns_tcphdr->flags() |= TH_ACK;
00422   if (tcpheader->urg == 1) 
00423         ns_tcphdr->flags() |= TH_URG;
00424 
00425 #endif  /* LINUX_TCP_HEADER */
00426 
00427 
00428   hdr_cmn *ns_cmnhdr = HDR_CMN(nspacket);
00429   ns_cmnhdr->size() = ntohs(ipheader->ip_len);
00430 
00431   Packet::free(p);
00432 
00433   // inject into simulator
00434   target_->recv(nspacket);
00435   return;
00436 }
00437 
00438 /*
00439  * ns scheduler calls TapAgent::dispatch which calls recvpkt.
00440  * 
00441  * recvpkt then calls the network (net_) to receive as many packets
00442  * as there are from the packet capture facility.
00443  * For every packet received through the callback, it converts to ns
00444  * FullTcp packet and injects it into the simulator by calling target_->recv
00445  * 
00446  */
00447 void
00448 TCPTapAgent::recvpkt()
00449 {
00450   if (net_->mode() != O_RDWR && net_->mode() != O_RDONLY) {
00451     fprintf(stderr,
00452             "TCPTapAgent(%s): recvpkt called while in write-only mode!\n",
00453             name());
00454     return;
00455   }
00456   
00457   int cc = net_->recv(pkt_handler, this);
00458   if (cc <= 0) {
00459     if (cc < 0) {
00460       perror("recv");
00461     }
00462     return;
00463   }
00464   TDEBUG4("%f: TCPTapAgent(%s): recvpkt, cc:%d\n", now(), name(), cc);
00465 
00466   // nothing to do coz pkt_handler would have called processpkt()
00467   // that would have injected packets into the simulator
00468 }
00469 
00470 
00471 
00472 
00473 /*
00474  * simulator schedules TapAgent::recv which calls sendpkt
00475  *
00476  * Grabs a ns Full TCP packet, converts it into real TCP packet 
00477  * and injects onto the network using net_->send
00478  *
00479  */
00480 int
00481 TCPTapAgent::sendpkt(Packet* p)
00482 {
00483   int byteswritten, datalen;
00484   unsigned char *packet;
00485   unsigned char received_ttl;
00486   int hlength = IP_HEADER_LEN + TCP_HEADER_LEN;
00487   struct tcphdr *tcpheader;
00488 
00489   if (net_->mode() != O_RDWR && net_->mode() != O_WRONLY) {
00490     fprintf(stderr,
00491             "TCPTapAgent(%s): sendpkt called while in read-only mode!\n",
00492             name());
00493     return (-1);
00494   }
00495   
00496   // send packet into the live network
00497   hdr_cmn* ns_cmnhdr = HDR_CMN(p);
00498   if (net_ == NULL) {
00499     fprintf(stderr,
00500             "TCPTapAgent(%s): sendpkt attempted with NULL net\n",
00501             name());
00502     drop(p);
00503     return (-1);
00504   }
00505   
00506   hdr_tcp* ns_tcphdr = HDR_TCP(p);
00507 
00508   hdr_ip * ns_iphdr = HDR_IP(p);
00509   received_ttl = ns_iphdr->ttl_;
00510 
00511   // Here we check if ns has sent any data in the packet.
00512   datalen = ns_cmnhdr->size() - ns_tcphdr->hlen();
00513   packet = (unsigned char *) calloc (1, sizeof(unsigned char) * 
00514                                      (hlength + datalen));
00515   if (packet == NULL) {
00516     fprintf(stderr,
00517             "TCPTapAgent(%s) : Error %d allocating memory.\n", name(), errno);
00518     return (-1);
00519   }
00520 
00521 
00522   // Create real world tcp packet.
00523   ip_gen((char *)packet, (unsigned char) IPPROTO_TCP, 
00524          nsnode.sin_addr, extnode.sin_addr, 
00525          hlength + datalen, received_ttl);
00526 
00527   tcpheader = (struct tcphdr*) (packet + IP_HEADER_LEN);
00528 
00529   tcp_gen((char *)tcpheader, nsnode.sin_port, extnode.sin_port, p);
00530 
00531 #ifndef LINUX_TCP_HEADER
00532   tcpheader->th_sum = trans_check(IPPROTO_TCP, (char *) tcpheader,
00533                                   sizeof(struct tcphdr) + datalen,
00534                                   nsnode.sin_addr, extnode.sin_addr);
00535 #else 
00536   tcpheader->check = trans_check(IPPROTO_TCP, (char *) tcpheader,
00537                                   sizeof(struct tcphdr) + datalen,
00538                                   nsnode.sin_addr, extnode.sin_addr);
00539 
00540 #endif 
00541 
00542   /* 
00543      Limits the packets going out to only IP + TCP header. 
00544      ns will act as an ACK machine.
00545    */
00546   byteswritten = net_->send(packet, hlength + datalen);
00547   if (byteswritten < 0) {
00548     fprintf(stderr,"TCPTapAgent(%s): sendpkt (%p, %d): %s\n",
00549             name(), p->accessdata(), ns_cmnhdr->size(), strerror(errno));
00550     Packet::free(p);
00551     free(packet);
00552     return (-1);
00553     
00554   }
00555   
00556   free(packet);
00557   TDEBUG3("TCPTapAgent(%s): sent packet (sz: %d)\n", name(), byteswritten);
00558   return 0;
00559 }
00560 
00561 
00562 
00563 
00564 
00565 
00566 
00567 

Generated on Tue Apr 20 12:14:36 2004 for NS2.26SourcesOriginal by doxygen 1.3.3