Final Project 4 - Multi-Core Network Honeypot

Last updated: 11 May 2011

I'm completely lost. Where do I get started? What files should I edit? (May 8)

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

Notes and experience on how to create kernel network drivers.

Resources (May 8)

Here are a few possibly useful resources:

Why aren't breakpoints working? (May 8)

As reported by a student, the simulator does not ever stop on a breakpoint due to a few bugs. To fix this, you can either:

Why isn't memset working? (May 8)

As reported by a student, memset erroneously sets memory far beyond the region it should be setting, nor does it set the entire region specified. This is caused by a few bugs in the function memset_by_fours. To fix this, you can either:

opcode not supported for LL/SC (May 8)

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

When hashing a packet, the whole packet should be hashed, headers, data, and all, exactly as it arrived from the network card.

puts newline (May 8)

According to C standards, puts() is supposed to print a newline after the string. The code in console.c doesn't. You can add it if you like. (Without the fix, GCC optimization can slightly mangle some outputs: GCC actually knows that printf() with a constant string ending in a newline is equivalent to puts() with the same constant but without the newline, and it will take advantage of this when optimizing.)

What's with the 0x55555555 values (May 9)

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 (May 9)

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;
}

Honeypot command packets with invalid commands (May 11)

A student pointed out a small bug in the simulator that would occasionally cause honeypot command packets to be generated with nonsense values in the command field.

The bug is in devices.c in the simulator source. To fix it:

rx_head and rx_tail (May 11)

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

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