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 ./kernel 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.

You should not need to modify anything in the top-level pa4 directory, unless we announce bugs in that code, as that contains the code for the simulator. You will be doing most of your work in kernel/kernel.c and any other files you choose to create.

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? (May 8)

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.

What do we do with packets that do not contain the secret? (May 9)

The honeypot.h header file says if a packet does not contain 0x3410 in the secret field, then "it isn't a real command packet, and should be ignored". The last half of this sentence is poorly worded.

Any packet that does not contain the correct secret is not a command packet, so it should be processed as a normal non-command packet, not completely ignored.

We have updated honeypot.h to include this correction.

Why do I get errors about multiple definitions if I include a header file? (May 10)

This is because the file is being included multiple times (say, once when you did it and once in kernel.h), and the authors of these header files did not see fit to include standard header guards. You can either remove the include or, the proper way, add the following to machine.h:

#ifndef MACHINE_H_
#define MACHINE_H_

... {contents of file} ...

#endif  // MACHINE_H_

This prevents the contents of the file from being added more than once, no matter how many times it gets included.

We have updated all header files to have these include guards.