Wanted: an NBD dissector for Ethereal

I could probably write it myself, given time, but I'm guessing it's going to cost me a lot more time understanding the Ethereal API than it is going to cost someone else undestanding the NBD protocol. Which is really simple. So, here's a short description of the protocol; now if someone could write me an Ethereal dissector, I'd be very happy. And if you need it, just ask for more information.

"Negotiation" phase:
  • Connection is opened by the client
  • The server sends out the literal string NBDMAGIC to the client (which is the "INIT_PASSWD" in the code and in error messages), followed by the the 'cliserv_magic', 0x00420281861253LL. The NBDMAGIC is there to identify a server; the cliserv_magic may be updated when the protocol changes incompatibly.
  • The server sends the size of the device as a 64 bit unsigned integer.
  • The server sends 128 bytes of zeroes (discarded by the client currently; these are reserved for further use)
(whether or not the above are all in one packet is something I don't know and don't really care about; they're all done using different write calls, so can technically be in different packets)
After that, the client is expected to be happy with the connection (if it isn't, it'll just drop the connection without explanation).
Main data pushing phase:
(I just made that name up, give it a reasonable name please ;-)
  • Clients sends a struct nbd_request to the server (which is defined in <linux/nbd.h>. The fields in that struct are:
    magic (32bit unsigned int)
    must be NBD_REQUEST_MAGIC aka 0x25609513 (again defined in <linux/nbd.h>); if it isn't, the server disconnects (this should really be handled better, but at the moment it isn't; and changing the protocol to do this might be less than trivial). It is possible that previous versions of the protocol used 0x12560953 instead (the header file mentions that as something not to be used, but I don't know where it comes from).
    type (32 bit unsigned int)
    is NBD_CMD_READ aka 0 (to read data), NBD_CMD_WRITE (to write data) aka 1, or NBD_CMD_DISC aka 2 (to request a clean disconnect).
    handle (char array of eight bytes)
    used to uniquely identify a request; this is later sent back in the reply, and can be used to associate a reply with a request.
    from (64 bit unsigned int)
    the offset in the export where the read or the write should start.
    len (32 bit unsigned int)
    the length of the requested read or write.
  • If struct nbd_request.type==NBD_CMD_WRITE, the client will then send struct nbd_request.len bytes to the server, containing the data it wants to see written.
  • Server sends a struct nbd_reply to the client:
    magic (32 bit unsigned int)
    functions similar to struct nbd_request.magic, only its value is supposed to be 0x67446698. Analoguous to struct nbd_request.magic, there's a value, possibly from a previous version of the protocol, which says 0x96744668 instead.
    error (32 bit unsigned integer)
    is zero, unless an error occurred
    handle (char array of eight bytes)
    the exact same value that was received in struct nbd_request.handle
  • If struct nbd_request.type==NBD_CMD_READ, the server will then send struct nbd_request.len bytes to the client, containing the data it read.

As you can see, a very simple protocol really... now if only somebody could write me a dissector—having to dissect it by hand isn't very funny, really.