University of Notre Dame NetScale Laboratory

Annotated Code - Adapter.cpp - Using libpcap

The following code is from the original RIPPS prototype. It drew upon the CheapLogger code as well. Notable demonstrations of functionality from libpcap include reading packets, writing packets, and interacting with the timestamp.

Quick Links

Functionality Code Function Detailed Description
Callback pkt_callback Handle packets received by libpcap as the registered callback function

/* Adapter.cpp
 **********************************************************
 * This code is part of the RIPPS (Rogue Identifying
 * Packet Payload Slicer) system developed at the University
 * of Notre Dame. 
 *
 * PI:       Dr. Aaron Striegel    striegel@nd.edu
 * Students: Chad Mano (lead)      Yingxin Jiang
 *           Dave Salyers          Dave Cieslak
 *           Qi Liao               Andrew Blaich   
 **********************************************************
 * Current Version:  $Revision: 1.2 $  $Date: 2008/05/08 18:48:44 $
 *                   checked in by $Author: AaronStriegel $ 
 **********************************************************
 */

#include <iostream>
using namespace std;

#include <pcap.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "Thread_Archive.h"
#include "Adapter.h"
#include "Thread_Input.h"
#include "Thread_Output.h"
#include "Input.h"
#include "MemoryPool.h"
#include "em_proto.h"
#include "Utils.h"
#include "Monitor.h"

Callback Function

The function listed below is for callback from libpcap. In short, one provides a callback function that libpcap then invokes when a packet has been received. For those of your familiar with interrupt service routines, the code will be quite similar. If your are less than familiar with callback routines, consider the following:

  • When you call a function, you typically list myFunction() to call it.
  • If you leave off the parentheses, the name of the function is an address much like when you leave off the brackets when accessing a pointer. The address of the function is a pointer, just like a normal pointer in the code. The trick is the arguments, i.e. how the function gets called.
  • For example, you could write in your code:

   void * pPointer;

   pPointer = (void *) pkt_callback; 

While the above discussion is not really necessary to understand what the function is doing, let's continue by decomposing the function.

  1. The adapter (an object in the RIPPS code encapsulating a libpcap-based adapter) is passed in as "argument" in the args pointer. Remember, a pointer is a pointer is a pointer and we can cast it however we see fit. The passing in of the adapter object allows the callback function to put the packet somewhere (i.e. in the queue of the adapter).
  2. A placeholder object is retrieved from the memory pool. Remember, dynamic memory allocation in global memory is expensive (malloc, new, etc.). Allocate once and then re-use the object or use a local variable.
  3. Check to make sure that libpcap really got the entire packet. I have yet to see this error ever in practice.
  4. Grab the timestamp from the libpcap struct. Note that libpcap stamps it when it receives it, not when we process it in our callback function. For all practical purposes, these numbers should be very similar.
  5. Copy (ugh) the entirety of the packet into another array. This is unfortunately a necessary evil unless we want to do all of our processing in the callback function. As RIPPS uses producer/consumer queues and slices packets, it goes for paying the performance penalty in exchange for easier programming.
  6. Check the packet to make sure it did not come from this host. This step is largely optional as libcap will detect application-level packets coming down as well.

void pkt_callback (u_char *args, const struct pcap_pkthdr *header, const u_char *packet) 
{
   Adapter * pAdapter;
   PacketHolder * pPacket;
   pAdapter = (Adapter *) args;
   
   pPacket = g_MemPool.getPacket();
   
   if(pPacket == NULL) {
      cerr << "Packet callback failed, no valid packet in the memory pool" << endl;
      return;
   }
   
   if(header->caplen != header->len) {
      cerr << "Warning: libpcap burped and didn't get us the whole packet, bailing on this packet" << endl;
      pAdapter->addInputPacket(NULL);      
      g_MemPool.releasePacket(pPacket);
      g_theMonitor.addStat(MONITOR_STAT_PCAP_ERR,1);
      return;
   }
   
   // For now, just do a full memory copy and eat it for simplicity until the code is modded
   memcpy(&pPacket->capTime, &header->ts, sizeof(struct timeval));
      
   memcpy(pPacket->byData, packet,  header->caplen);
   pPacket->nLength = header->caplen;
   pPacket->nCapAdp = pAdapter->getLocation();
      
   //cout << "  Rcvd a packet of " << header->caplen << " bytes on " << pAdapter->getDevName() << "!" << endl;
               
   if(memcmp(pPacket->byData+OFFSET_ETH_SRCMAC, pAdapter->getMAC(), 6) == 0) {
      // This packet came from us!
      //cout << "  Self!" << endl;
      pAdapter->addInputPacket(NULL);      
      g_MemPool.releasePacket(pPacket);
   } 
   else {
      //pPacket->dumpPacketParse();
     //g_theArchive.archiveString("R Pkt: ");
     //g_theArchive.archivePacket(pPacket);
      pAdapter->addInputPacket(pPacket);
      //cout << " Pkt Arr: " << pPacket->capTime.tv_sec << " s, " << pPacket->capTime.tv_usec << endl;   
   }
}

Adapter::Adapter () {
   strncpy(m_szDevName, "UNKNOWN",PCAP_DEVICE_NAME_LEN);
   m_nLocation = LOCATION_UNDEFINED;
   m_pDevice = NULL;
   m_bRunning = 1;
   m_pLinkAdapter = NULL;
   m_pInput = NULL;
   m_pInputPacket = NULL;
}

Adapter::~Adapter () {

}

ether_addr * Adapter::getMAC () {
   return &m_MAC;
}

void Adapter::dumpInfo () {
   int      j;

   cout << "Adapter: " << m_szDevName << endl;
   
   printf("  MAC: ");
   
   for(j=0; j<6; j++) {
      printf("%02X", (unsigned char) m_MAC.ether_addr_octet[j]);
   }
      
   printf("  IP: ");
   dumpIPv4(m_byIP);
   cout << endl;      
      
   cout << "  Out Queue: " << getOutQueueSize() << " (RQ: " << m_OutBuffer.size() << ")" << endl;
   printf("\n");
}
   

void Adapter::addInputPacket (PacketHolder * pPacket) {
   //pthread_mutex_lock(&m_MutexInBuf);
   m_pInputPacket = pPacket;
   //pthread_mutex_unlock(&m_MutexInBuf);   
}

Opening the Lipbcap Device

The openDevice functions covers much of the base functionality of opening a libpcap device. Annotations are included in-line with the code.

int Adapter::openDevice () {
   char errbuf[PCAP_ERRBUF_SIZE];
   int    nResult;

The m_szDevName variable contains the C-style string of the name of the device (eth1, bge0, etc.). The name itself MUST correspond to an adapter on the machine that is visible via ifconfig.

   if(strcmp(m_szDevName, "UNKNOWN") == 0) {
      cerr << "No name specified for adapter, exiting...." << endl;
      exit(-1);
   }
   
   cout << "Device Name: " << m_szDevName << endl;

RIPPS employs several mutexes (mutual exclusion protection) for the input and output buffers. In short, a mutex allows a specific operation to be made atomic such that a given sequence of commands will be thread-safe. RIPPS employs the pthread mutex.

   // Initialize mutex on output buffer
   pthread_mutex_init(&m_MutexOutBuf, NULL);
   pthread_mutex_init(&m_MutexInBuf, NULL);

The libpcap device is opened for live (i.e. running right now, not reading from a file) operation.

Update (May 2008): Do not use BUFSIZ, use your own define value as this can vary on non-Linux systems. Hack away though if you are on Linux.

   m_pDevice = pcap_open_live(m_szDevName,BUFSIZ,1,1,errbuf);
   
   if(m_pDevice == NULL) {
      cerr << "Libpcap open live device failed for " << m_szDevName << endl;
      cerr << "  " << errbuf << endl;
      return -1;
   }
   
   cout << "Opened up device " << m_szDevName << " successfully..." << endl;

Support for setting the device into non-blocking mode (i.e. a call to read a packet does not block until it gets one) was problematic depending upon the system employed.

/*   if(pcap_setnonblock(m_pDevice, 1, errbuf) <= 0) {
      cerr << "Unable to set " << m_szDevName << " into non-blocking mode" << endl;
      cerr << " Error is " << errbuf << endl;
      pcap_perror(m_pDevice, errbuf);
      cerr << "Try #2: " << errbuf << endl;
      exit(-1);
   }   */

   
   find_my_address(pcap_fileno(m_pDevice), m_szDevName, &m_MAC);
   
   // Start up the output thread
   nResult = pthread_create(&m_ThreadOutput, NULL, Thread_Output, (void *) this);
   if(nResult) {
      cerr << "* Error creating output thread for adapter " << m_szDevName << endl;
      cerr << "    Code: " << nResult << endl;
      exit(-1);
   }
   
   cout << "   Output thread started for " << m_szDevName << endl;
   
   // Start up the input thread
   nResult = pthread_create(&m_ThreadInput, NULL, Thread_Input, this);
   if(nResult) {
      cerr << "* Error creating output thread for adapter " << m_szDevName << endl;
      cerr << "    Code: " << nResult << endl;
      exit(-1);
   }
   
   cout << "   Input thread started for " << m_szDevName << endl;
   
   return 0;
}

int Adapter::writePacket   (PacketHolder * pPacket) {
   int      nBytes;
   
   char   bCallback;
   
   bCallback = 0;
   
   //pPacket->dumpPacketParse();
   //sleep(5);
   
   if(g_theMonitor.getDebug_ShowWrite()) {
      cout << "Output adapter " << m_szDevName << " write  ( " << pPacket->nLength << " bytes)" << endl;
   }
   
   //dumpInfo();
   //pPacket->dumpPacketParse();
   
   //sleep(1);
   
   if(pPacket->bCallBack) {
      // Get the system time and re-apply it as the capture time
      struct timeval      curTime;
   
      // What is the current system time?
      gettimeofday(&curTime, NULL);
            
      pPacket->capTime = curTime;
      
      pPacket->doCallback();
      bCallback = 1;
   }
   
   nBytes = write(pcap_fileno(m_pDevice), pPacket->byData, pPacket->nLength);
   
   //g_theArchive.archiveString("W Pkt: ");
   //g_theArchive.archivePacket(pPacket);

   if(bCallback) {
      //cout << " Callback initiated" << endl;
   }
   
   //cout << "Write complete!" << endl;
   
   
   return nBytes;
}

InterfaceInput * Adapter::getInterfaceInput () {
   return m_pInput;
}

void Adapter::setInterfaceInput (InterfaceInput * pInput) {
   m_pInput = pInput;
   
   if(m_pInput != NULL) {
      m_pInput->setAdapter(this);
   }
}

char * Adapter::getDevName () {
   return m_szDevName;
}


void Adapter::setDevName (char * pDevName) {
   cout << "Setting device name to " << pDevName << endl;
   strncpy(m_szDevName, pDevName,PCAP_DEVICE_NAME_LEN);
}

      
char Adapter::getLocation () {
   return  m_nLocation;
}


void Adapter::setLocation (char bLoc) {
   m_nLocation = bLoc;
}

      
int Adapter::getPacket (PacketHolder ** ppPacket) {
   if(m_pInput == NULL) {
      cerr << "Warning: Input interface not yet enabled for adapter " << m_szDevName << endl;
      return -1;
   }
   
   if(ppPacket == NULL) {
      cerr << "Error: Packet pointer was NULL in Adapter::getPacket" << endl;
      return -2;
   }
   
   //pcap_loop(m_pDevice,1,pkt_callback,(u_char *) this);
   
   pcap_dispatch(m_pDevice,1,pkt_callback,(u_char *) this);

   if(m_pInputPacket != NULL) {
      *ppPacket = m_pInputPacket;
      
      if(m_nLocation == LOCATION_EXTERNAL && g_theMonitor.getDebug_ShowRead_External()) {      
         cout << m_szDevName << " ";
         (*ppPacket)->dumpBrief();
      } else if (m_nLocation == LOCATION_MONITOR && g_theMonitor.getDebug_ShowRead_Internal()) {      
         cout << m_szDevName << " ";
         (*ppPacket)->dumpBrief();
      }   
      
      return 0;
   } else {
      *ppPacket = NULL;
      return -1;
   }
}
      
void Adapter::addOutPacket (PacketHolder * pPacket) {
   pthread_mutex_lock(&m_MutexOutBuf);
   
   if(pPacket->bRestrictedRelease) {
      if(g_theMonitor.getSliceDelay() > 0) {
         pushShapeBuffer(pPacket);
      } else {
         m_OutBuffer.push_back(pPacket);
      }
   } else {
      m_OutBuffer.push_back(pPacket);
   }
   
   pthread_mutex_unlock(&m_MutexOutBuf);
}

void Adapter::pushShapeBuffer (PacketHolder * pPacket) {
   m_ShapeBuffer.push_back(pPacket);      
}

char Adapter::releaseShapeBuffer () {
   struct timeval      curTime;
   int            j;
   vector<PacketHolder *>::iterator   theIt;
   PacketHolder   *   pPacket;
   char bRelease = 0;
   
   pthread_mutex_lock(&m_MutexOutBuf);   
   
   // What is the current system time?
   gettimeofday(&curTime, NULL);

   while(m_ShapeBuffer.size() > 0) {      
      theIt = m_ShapeBuffer.begin();
   
      pPacket = *(theIt);
   
      //if(m_ShapeBuffer.size() > 1) {
      //   cout << "Attempting to release the shape buffer (" << m_ShapeBuffer.size() << " pkts)" << endl;         
      //   cout << "   Cur Time: " << curTime.tv_sec << "." << curTime.tv_usec << endl;
      //   cout << "   1st packet has time of " << pPacket->releaseTime.tv_sec << "." << pPacket->releaseTime.tv_usec << endl;
      //}
   
      if(pPacket->canRelease(&curTime)) {
         //if(m_ShapeBuffer.size() > 1) {
         //   cout << "  Shape buffer release" << endl;
         //}
         
         pPacket->clearRestrict();
         pPacket->capTime = curTime;
         
         m_OutBuffer.push_back(pPacket);
         m_ShapeBuffer.erase(theIt);   
         
         bRelease = 1;
         
         // Should this be limited to one packet per iteration of the thread such that we don't
         // stamp a bunch enqueue with the wrong release time
         if(g_theMonitor.getLimitShapeRelease()) {
            // Limiting release to one per packet
            break;
         }
         
      } else {
         break;
      }      
   }   
   
   pthread_mutex_unlock(&m_MutexOutBuf);   
   return bRelease;
}

PacketHolder * Adapter::getNextOutPacket () {
   PacketHolder   *   pPacket;
   vector<PacketHolder *>::iterator   theIt;

   pthread_mutex_lock(&m_MutexOutBuf);
   
   if(m_OutBuffer.size() > 0) {
      theIt = m_OutBuffer.begin();
   
      pPacket = *(theIt);
      m_OutBuffer.erase(m_OutBuffer.begin());
      
      pthread_mutex_unlock(&m_MutexOutBuf);
      
      // Return the first packet in the queue
      return pPacket;
   } else {
      pthread_mutex_unlock(&m_MutexOutBuf);   
      return NULL;
   }
}

void   Adapter::setIP (char * pIP, int nLength) {
   if(nLength > DEFAULT_IP_LEN) {
      cerr << "  Unable to set IP address to something more than IPv4 (4 bytes) " << endl;
      return;
   }
   
   if(nLength < DEFAULT_IP_LEN) {
      cerr << "  Bad length of IPv4 address, less than 4 bytes" << endl;
      cerr << "   Length = " << nLength << endl;
      return;
   }      
   
   memcpy(m_byIP, pIP, DEFAULT_IP_LEN);
   m_nIPLength = DEFAULT_IP_LEN;
}



int Adapter::getOutQueueSize () {
   int         nQueue;
   
   nQueue = m_OutBuffer.size() + m_ShapeBuffer.size();
   
   return nQueue;
}

void Adapter::checkOutReleaseShape () {
}

void Adapter::setRunning (char bRunning) {
   m_bRunning = bRunning;
}

char Adapter::isRunning () {
   return m_bRunning;
}

void Adapter::linkAdapter (Adapter * pAdapter) {
   m_pLinkAdapter = pAdapter;
   
   if(m_pInput != NULL) {
      m_pInput->linkAdapter(m_pLinkAdapter);
   }
}

void Adapter::stampSrcMAC (PacketHolder * pPacket) {
   memcpy(pPacket->byData+OFFSET_ETH_SRCMAC, m_MAC.ether_addr_octet, ETH_MAC_LENGTH);
}

void Adapter::dumpARP () {
   int         j;
   ARPEntry   *   pEntry;
   
   cout << "ARP Table for Adapter " << m_szDevName << endl;
   cout << "  " << m_ARPTable.size() << " entries" << endl; 
   
   for(j=0; j<m_ARPTable.size(); j++) {
      pEntry = m_ARPTable[j];   
      
      printf("    %3d  ", j);
      
      if(pEntry->m_bResolved) {
         cout << "R  ";
      } else {
         cout << "P  ";
      }
      
      dumpIPv4(pEntry->m_byIP);
      
      cout << " ";
      
      if(pEntry->m_bResolved) {
         dumpHex(pEntry->m_byMAC, ':', 6);
      }
      
      cout << endl;
   }         
}

ARPEntry * Adapter::findARP (char * pIP) {
   int         j;
   ARPEntry   *   pEntry;
   
   //cout << " Searching ARP table for IP address ";
   //dumpIPv4(pIP);
   //cout << endl;
   
   for(j=0; j<m_ARPTable.size(); j++) {
      pEntry = m_ARPTable[j];
      
      if(memcmp(pEntry->m_byIP, pIP, DEFAULT_IP_LEN) == 0) {
         return pEntry;
      }
   }
   
   return NULL;
}

void Adapter::sendARP (ARPEntry * pARP) {
   PacketHolder *   pHolder;
   
   // Get a fresh packet
   pHolder = g_MemPool.getPacket();
   
   // Stamp the destination address with the broadcast address
   memset(pHolder->byData+OFFSET_ETH_DSTMAC, 0xFF, DEFAULT_MAC_LEN); 

   // Stamp the source as us
   stampSrcMAC(pHolder);
   
   pHolder->byData[OFFSET_ETH_TYPELEN+0] = ETH_TYPELEN_ARP_B1;
   pHolder->byData[OFFSET_ETH_TYPELEN+1] = ETH_TYPELEN_ARP_B2;
   
   // Stamp the packet now with pre-defined fields
   pHolder->byData[L2_OFFSET+0] = 0x00;
   pHolder->byData[L2_OFFSET+1] = 0x01;

   pHolder->byData[L2_OFFSET+2] = ETH_TYPELEN_IP_B1;
   pHolder->byData[L2_OFFSET+3] = ETH_TYPELEN_IP_B2;
   
   pHolder->byData[L2_OFFSET+4] = DEFAULT_MAC_LEN;
   pHolder->byData[L2_OFFSET+5] = DEFAULT_IP_LEN;
   
   pHolder->byData[L2_OFFSET+6] = 0x00;
   pHolder->byData[L2_OFFSET+7] = 0x01;
   
   // OK, add in our info
   
   // Our Src MAC address
   memcpy(pHolder->byData+L2_OFFSET+8, m_MAC.ether_addr_octet, DEFAULT_MAC_LEN);
   
   // Our adapter IP address
   memcpy(pHolder->byData+L2_OFFSET+8+DEFAULT_MAC_LEN, m_byIP, DEFAULT_IP_LEN);
   
   // Don't know this field, this is the field we will get our response in
   memset(pHolder->byData+L2_OFFSET+8+DEFAULT_MAC_LEN+DEFAULT_IP_LEN, 0, DEFAULT_MAC_LEN);
   
   // What IP do we want?
   memcpy(pHolder->byData+L2_OFFSET+8+DEFAULT_MAC_LEN+DEFAULT_IP_LEN+DEFAULT_MAC_LEN, pARP->m_byIP, DEFAULT_IP_LEN);
   
   pHolder->nLength = L2_OFFSET+8+DEFAULT_MAC_LEN*2+DEFAULT_IP_LEN*2;
   
   //cout << "Sent ARP packet breakdown on adapter " << m_szDevName << "!" << endl;
   //dumpParseARP(pHolder->byData);
   
   //cout << "-> Raw Packet Breakdown" << endl;
   //pHolder->dumpPacketParse();
   
   writePacket(pHolder);
   g_MemPool.releasePacket(pHolder);
}

void Adapter::processARP (PacketHolder * pPacket) {
   // 
   //cout << "*************************" << endl;
   //cout << "Processing an ARP response" << endl;
   //pPacket->dumpPacketParse();

   // Double check a few of the fields just to be sure   
   if(pPacket->byData[L2_OFFSET+0] != 0x00 || pPacket->byData[L2_OFFSET+1] != 0x01) {
      cout << "  Ignoring ARP - unknown H/W type" << endl;
      g_MemPool.releasePacket(pPacket);      
      return;
   }
   
   if(pPacket->byData[L2_OFFSET+2] != ETH_TYPELEN_IP_B1 || pPacket->byData[L2_OFFSET+3] != ETH_TYPELEN_IP_B2) {
      cout << "  Ignoring ARP - unknown protocol type" << endl;
      g_MemPool.releasePacket(pPacket);      
      return;
   }

   if(pPacket->byData[L2_OFFSET+4] != DEFAULT_MAC_LEN) {
      cout << "  Ignoring ARP - MAC address is not 6 bytes" << endl;
      g_MemPool.releasePacket(pPacket);      
      return;
   }
      
   if(pPacket->byData[L2_OFFSET+5] != DEFAULT_IP_LEN) {
      cout << "  Ignoring ARP - IP address is not 4 bytes" << endl;
      g_MemPool.releasePacket(pPacket);      
      return;
   }
   
   if(pPacket->byData[L2_OFFSET+6] != 0x00 || pPacket->byData[L2_OFFSET+7] != 0x02) {
      // Silently discard this, it is likely an ARP request which we don't care about
      //cout << " Ignoring request ARP" << endl;
      //printf("   Op Field: %02X\n", pPacket->byData[L2_OFFSET+7]);
      //pPacket->dumpPacketParse();
      //dumpParseARP(pPacket->byData);
      g_MemPool.releasePacket(pPacket);
      return;         
   }
   
   /*
   // Whoot, if we got this far, we should be good
   cout << "  Breaking down the ARP" << endl;
   
   cout << "     Src MAC: ";
   dumpHex(pPacket->byData+L2_OFFSET+8, ':', DEFAULT_MAC_LEN);
   cout << endl;
   
   cout << "     Src IP: ";
   dumpIPv4(pPacket->byData+8+L2_OFFSET+DEFAULT_MAC_LEN);
   cout << endl;

   cout << "     Dst MAC: ";
   dumpHex(pPacket->byData+8+L2_OFFSET+DEFAULT_MAC_LEN+DEFAULT_IP_LEN, ':', DEFAULT_MAC_LEN);
   cout << endl;
   
   cout << "     Dst IP: ";
   dumpIPv4(pPacket->byData+8+L2_OFFSET+DEFAULT_MAC_LEN*2+DEFAULT_IP_LEN);
   cout << endl;
   */

   ARPEntry   *   pEntry;
   
   pEntry = findARP(pPacket->byData+8+L2_OFFSET+DEFAULT_MAC_LEN);
   
   if(pEntry == NULL) {
      cout << "Error - no entry exists in the ARP table despite us being the one" << endl;
      cout << "  that requested it.  Hmmmmm" << endl;
      g_MemPool.releasePacket(pPacket);   
      return;
   }
   
   memcpy(pEntry->m_byMAC, pPacket->byData+L2_OFFSET+8, DEFAULT_MAC_LEN);
   pEntry->m_bResolved = 1;
   
   // Need to dispatch pending packets too
   
   PacketHolder *       pARPQueue;
   unsigned int      k;
   
   for(k=0; k<pEntry->m_Pending.size(); k++) {
      pARPQueue = pEntry->m_Pending[k];
      
      if(!routePacket(pARPQueue)) {
         // Gobble it and silently discard
         g_MemPool.releasePacket(pARPQueue);
         continue;
      } else {
         writePacket(pARPQueue);
         g_MemPool.releasePacket(pARPQueue);         
      }            
   }
   
   pEntry->m_Pending.clear();
   
   g_MemPool.releasePacket(pPacket);
}

// 0 means we gobbled it, 1 means it is yours to take

char Adapter::routePacket (PacketHolder * pPacket) {
   // If we are in pass through, our life is extremly simple
   if(!g_theMonitor.shouldRoutePackets()) {
      return 1;      
   }

   // In routing mode, if so do lots of things   
   stampSrcMAC(pPacket);
   
   // If the packet is not IP, squelch it entirely
   if(isPacketIP(pPacket->byData, pPacket->nLength) == 0) {
      cout << "Squelching non-IP packet" << endl;
      cout.flush();
      //pPacket->dumpPacketParse();
   
      // Make sure it is not an ARP response packet
      if(isPacketARP (pPacket->byData, pPacket->nLength) == 0) {
         // Is it coming to us?
         if(memcmp(pPacket->byData+OFFSET_ETH_DSTMAC, m_MAC.ether_addr_octet, DEFAULT_MAC_LEN) == 0) {
            processARP(pPacket);
            return 0;
         } else {
            // Nope, just ignore it as we weren't the source
         }
      }
   
      // Eat the packet, mmmm P is for packet!
      g_MemPool.releasePacket(pPacket);
      return 0;
   }
   
   // OK, let's see if the destination is local (1 hop) or will be reached via the gateway (not local)
   
   // It is local
   
   //  See if we have this in our local ARP cache (yes, it is redundant but hey, what can you do)?
   ARPEntry   *   pARP;
   
   pARP = findARP (pPacket->byData+L2_OFFSET+OFFSET_IPV4_PROTOCOL_DSTIP);
   
   if(pARP == NULL) {
      //cout << " Need to ARP for this one!" << endl;
   
      // Gobble it into our own personal queue and send out an ARP request
   
      // Create a new ARP entry
      pARP = new ARPEntry();
      memcpy(pARP->m_byIP, pPacket->byData+L2_OFFSET+OFFSET_IPV4_PROTOCOL_DSTIP, DEFAULT_IP_LEN);
      pARP->m_nIPLength = DEFAULT_IP_LEN;
      pARP->m_bResolved = 0;
      
      m_ARPTable.push_back(pARP);

      // Add this to a queue of pending ARP requests   
      pARP->m_Pending.push_back(pPacket);
   
      // Send out an ARP for that address
      sendARP (pARP);
      return 0;
      
   } else if(!pARP->m_bResolved) {
      // Waiting on a response, gobble it
      pARP->m_Pending.push_back(pPacket);
      return 0;
   } else {
      // Got it, stamp that puppy with a destination address
      memcpy(pPacket->byData+OFFSET_ETH_DSTMAC, pARP->m_byMAC, ETH_MAC_LENGTH);
      return 1;
   }
}

r2 - 08 May 2008 - 18:48:44 - AaronStriegel
This site is powered by the TWiki collaboration platformCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback
Syndicate this site RSSATOM