Final Project 4 - Multi-Core Network Honeypot

I'm completely lost. Where do I get started? What files should I edit?

To start working on the project, we suggest that you read the following files in the pa4 directory carefully at the very minimum: honeypot.h, kernel.h/kernel.c, and machine.h. To understand how input and output drivers work, you should also read console.h/console.c and keyboard.h/keyboard.c. This will also make it easier for you to implement your own network driver.

The first task is to implement a working network driver; it is suggested that you put everything related to your network driver in a new file named network.c or something similar. To figure out how to implement this network driver, look to keyboard.c for an example of what the driver does: First it must scan the array of devices until it finds a device of the correct device, then it initializes that device. In the case of the network card, initialization will involve allocating space for the ring buffer and the DMA slots inside it.

After your network driver is done, then you can start implementing code in the __boot function in kernel.c to analyze the packets you are receiving.

Creating Kernel Network Drivers
Notes and experience on how to create kernel network drivers.
Resources

Here are a few possibly useful resources:

opcode not supported for LL/SC

Some people are getting gcc errors simililar to this:

  lock.s: Assembler messages:
  lock.s:11: Error: opcode not supported on this processor: mips1 (mips1) `ll $8,($4)'
  lock.s:18: Error: opcode not supported on this processor: mips1 (mips1) `sc $9,($4)'
  make: *** [lock.o] Error 1

Just add the following line before the LL or SC lines:

  .set mips2

Explanation: LL and SC were not part of the MIPS I instruction set architecture. They were added in MIPS II. The simulator only supports MIPS I plus a few bits of MIPS II. So by default, we compile for mips1, but when neded we have to tell gcc that it is okay to use MIPS II instructions by using the above assembler directive for mips2.

Clarification: the whole packet should be hashed
When hashing a packet, the whole packet should be hashed, headers, data, and all, exactly as it arrived from the network card.
What's with the 0x55555555 values
At the start of the simulation, before the kernel is loaded, the simulator fills all of physical memory with 0x55 bytes. This is done for debugging purposes: any time you see 0x55555555 in one of your variables, it is almost certainly due to using uninitialized memory.
Hash code for djb2
Here is the code for the djb2 hash function:
unsigned long djb2(unsigned char *pkt, int n)
{
  unsigned long hash = 5381;
  int c;
  for (int i = 0; i < n; i++) {
    c = pkt[i];
    hash = hash * 33 + c;
    //hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
  }
  return hash;
}
Here is a slightly optimized version:
unsigned long djb2(unsigned char *pkt, int n)
{
  unsigned long hash = 5381;
  int i = 0;
  while (i < n-8) {
    hash = hash * 33 + pkt[i++];
    hash = hash * 33 + pkt[i++];
    hash = hash * 33 + pkt[i++];
    hash = hash * 33 + pkt[i++];
    hash = hash * 33 + pkt[i++];
    hash = hash * 33 + pkt[i++];
    hash = hash * 33 + pkt[i++];
    hash = hash * 33 + pkt[i++];
  }
  while (i < n)
    hash = hash * 33 + pkt[i++];
  return hash;
}
rx_head and rx_tail
rx_head and rx_tail are indices into the ring buffer. They are not addresses, either physical or virtual.
Why am I getting truncation errors?

If you are trying to debug your network driver (using a flag such as -vvv:net), one of the errors you may see is "network card: packet truncation error (pkt is X bytes, buffer is Y bytes)", causing you to indignantly protest that you clearly set the dma_len field of your dma_ring_slot to be larger than Y!

What happened here is most likely that the network card changed the value of the dma_len field. Whenever the network card copies over a packet into the ring buffer, it sets the dma_len field of the corresponding dma_ring_slot to be the length of the packet. If you choose to reuse the same ring slots but don't reset the length field, you start seeing truncation errors, and the maximum length of the packets you can accept will start decreasing steadily...

I'm missing some evil packets, even though I'm adding an entry for every command packet that tells me to. What's wrong?

There is a subtle case here that might cause problems. Suppose a command packet arrives telling you that a packet with hash x is an evil packet. Immediately after, a packet comes with hash value x. If the second packet is processed before the command packet is, then the count for this evil packet is missed.

There are several reasons for why this can happen. A reader/writer lock that does not care about fairness might let the core that processes the evil packet to read the list of evil packets before letting the core that processes the command packet update the list (recall that reader/writer locks may allow any readers to lock while there are other readers, while writers needs to have exclusive access. This means that a flood of readers might starve writers from access). Another possibility is simply sending the packets to cores with a varying workload, and the evil packet was processed first on a ligher loaded core.

It is not a strict requirement that you enforce the exact order of the packets being processed, but it will be viewed favorably if you can manage to avoid missing evil packets from this subtle scenario.