proto_register_rpcap (void)
{
  static hf_register_info hf[] = {
    /* Common header for all messages */
    { &hf_version,
      { "Version", "rpcap.version", FT_UINT8, BASE_DEC,
        NULL, 0x0, NULL, HFILL } },
    { &hf_type,
      { "Message type", "rpcap.type", FT_UINT8, BASE_DEC,
        VALS(message_type), 0x0, NULL, HFILL } },
    { &hf_value,
      { "Message value", "rpcap.value", FT_UINT16, BASE_DEC,
        NULL, 0x0, NULL, HFILL } },
    { &hf_plen,
      { "Payload length", "rpcap.len", FT_UINT32, BASE_DEC,
        NULL, 0x0, NULL, HFILL } },

    /* Error */
    { &hf_error,
      { "Error", "rpcap.error", FT_STRING, BASE_NONE,
        NULL, 0x0, "Error text", HFILL } },
    { &hf_error_value,
      { "Error value", "rpcap.error_value", FT_UINT16, BASE_DEC,
        VALS(error_codes), 0x0, NULL, HFILL } },

    /* Packet header */
    { &hf_packet,
      { "Packet", "rpcap.packet", FT_NONE, BASE_NONE,
        NULL, 0x0, "Packet data", HFILL } },
    { &hf_timestamp,
      { "Arrival time", "rpcap.time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
        NULL, 0x0, NULL, HFILL } },
    { &hf_caplen,
      { "Capture length", "rpcap.cap_len", FT_UINT32, BASE_DEC,
        NULL, 0x0, NULL, HFILL } },
    { &hf_len,
      { "Frame length", "rpcap.len", FT_UINT32, BASE_DEC,
        NULL, 0x0, "Frame length (off wire)", HFILL } },
    { &hf_npkt,
      { "Frame number", "rpcap.number", FT_UINT32, BASE_DEC,
        NULL, 0x0, NULL, HFILL } },

    /* Authentication request */
    { &hf_auth_request,
      { "Authentication", "rpcap.auth", FT_NONE, BASE_NONE,
        NULL, 0x0, NULL, HFILL } },
    { &hf_auth_type,
      { "Authentication type", "rpcap.auth_type", FT_UINT16, BASE_DEC,
        VALS(auth_type), 0x0, NULL, HFILL } },
    { &hf_auth_slen1,
      { "Authentication item length 1", "rpcap.auth_len1", FT_UINT16, BASE_DEC,
        NULL, 0x0, NULL, HFILL } },
    { &hf_auth_slen2,
      { "Authentication item length 2", "rpcap.auth_len2", FT_UINT16, BASE_DEC,
        NULL, 0x0, NULL, HFILL } },
    { &hf_auth_username,
      { "Username", "rpcap.username", FT_STRING, BASE_NONE,
        NULL, 0x0, NULL, HFILL } },
    { &hf_auth_password,
      { "Password", "rpcap.password", FT_STRING, BASE_NONE,
        NULL, 0x0, NULL, HFILL } },

    /* Open request */
    { &hf_open_request,
      { "Open request", "rpcap.open_request", FT_STRING, BASE_NONE,
        NULL, 0x0, NULL, HFILL } },

    /* Open reply */
    { &hf_open_reply,
      { "Open reply", "rpcap.open_reply", FT_NONE, BASE_NONE,
        NULL, 0x0, NULL, HFILL } },
    { &hf_linktype,
      { "Link type", "rpcap.linktype", FT_UINT32, BASE_DEC,
        NULL, 0x0, NULL, HFILL } },
    { &hf_tzoff,
      { "Timezone offset", "rpcap.tzoff", FT_UINT32, BASE_DEC,
        NULL, 0x0, NULL, HFILL } },

    /* Start capture request */
    { &hf_startcap_request,
      { "Start capture request", "rpcap.startcap_request", FT_NONE, BASE_NONE,
        NULL, 0x0, NULL, HFILL } },
    { &hf_snaplen,
      { "Snap length", "rpcap.snaplen", FT_UINT32, BASE_DEC,
        NULL, 0x0, NULL, HFILL } },
    { &hf_read_timeout,
      { "Read timeout", "rpcap.read_timeout", FT_UINT32, BASE_DEC,
        NULL, 0x0, NULL, HFILL } },
    { &hf_flags,
      { "Flags", "rpcap.flags", FT_UINT16, BASE_DEC,
        NULL, 0x0, "Capture flags", HFILL } },
    { &hf_flags_promisc,
      { "Promiscuous mode", "rpcap.flags.promisc", FT_BOOLEAN, 16,
        TFS(&tfs_enabled_disabled), FLAG_PROMISC, NULL, HFILL } },
    { &hf_flags_dgram,
      { "Use Datagram", "rpcap.flags.dgram", FT_BOOLEAN, 16,
        TFS(&tfs_yes_no), FLAG_DGRAM, NULL, HFILL } },
    { &hf_flags_serveropen,
      { "Server open", "rpcap.flags.serveropen", FT_BOOLEAN, 16,
        TFS(&open_closed), FLAG_SERVEROPEN, NULL, HFILL } },
    { &hf_flags_inbound,
      { "Inbound", "rpcap.flags.inbound", FT_BOOLEAN, 16,
        TFS(&tfs_yes_no), FLAG_INBOUND, NULL, HFILL } },
    { &hf_flags_outbound,
      { "Outbound", "rpcap.flags.outbound", FT_BOOLEAN, 16,
        TFS(&tfs_yes_no), FLAG_OUTBOUND, NULL, HFILL } },
    { &hf_client_port,
      { "Client Port", "rpcap.client_port", FT_UINT16, BASE_DEC,
        NULL, 0x0, NULL, HFILL } },

    /* Start capture reply */
    { &hf_startcap_reply,
      { "Start capture reply", "rpcap.startcap_reply", FT_NONE, BASE_NONE,
        NULL, 0x0, NULL, HFILL } },
    { &hf_bufsize,
      { "Buffer size", "rpcap.bufsize", FT_UINT32, BASE_DEC,
        NULL, 0x0, NULL, HFILL } },
    { &hf_server_port,
      { "Server port", "rpcap.server_port", FT_UINT16, BASE_DEC,
        NULL, 0x0, NULL, HFILL } },
    { &hf_dummy,
      { "Dummy", "rpcap.dummy", FT_UINT16, BASE_DEC,
        NULL, 0x0, NULL, HFILL } },

    /* Filter */
    { &hf_filter,
      { "Filter", "rpcap.filter", FT_NONE, BASE_NONE,
        NULL, 0x0, NULL, HFILL } },
    { &hf_filtertype,
      { "Filter type", "rpcap.filtertype", FT_UINT16, BASE_DEC,
        NULL, 0x0, "Filter type (BPF)", HFILL } },
    { &hf_nitems,
      { "Number of items", "rpcap.nitems", FT_UINT32, BASE_DEC,
        NULL, 0x0, NULL, HFILL } },

    /* Filter BPF instruction */
    { &hf_filterbpf_insn,
      { "Filter BPF instruction", "rpcap.filterbpf_insn", FT_NONE, BASE_NONE,
        NULL, 0x0, NULL, HFILL } },
    { &hf_code,
      { "Op code", "rpcap.opcode", FT_UINT16, BASE_HEX,
        NULL, 0x0, "Operation code", HFILL } },
    { &hf_code_class,
      { "Class", "rpcap.opcode.class", FT_UINT16, BASE_HEX,
        VALS(bpf_class), 0x07, "Instruction Class", HFILL } },
    { &hf_code_fields,
      { "Fields", "rpcap.opcode.fields", FT_UINT16, BASE_HEX,
        NULL, 0xF8, "Class Fields", HFILL } },
    { &hf_code_ld_size,
      { "Size", "rpcap.opcode.size", FT_UINT16, BASE_HEX,
        VALS(bpf_size), 0x18, NULL, HFILL } },
    { &hf_code_ld_mode,
      { "Mode", "rpcap.opcode.mode", FT_UINT16, BASE_HEX,
        VALS(bpf_mode), 0xE0, NULL, HFILL } },
    { &hf_code_alu_op,
      { "Op", "rpcap.opcode.aluop", FT_UINT16, BASE_HEX,
        VALS(bpf_alu_op), 0xF0, NULL, HFILL } },
    { &hf_code_jmp_op,
      { "Op", "rpcap.opcode.jmpop", FT_UINT16, BASE_HEX,
        VALS(bpf_jmp_op), 0xF0, NULL, HFILL } },
    { &hf_code_src,
      { "Src", "rpcap.opcode.src", FT_UINT16, BASE_HEX,
        VALS(bpf_src), 0x08, NULL, HFILL } },
    { &hf_code_rval,
      { "Rval", "rpcap.opcode.rval", FT_UINT16, BASE_HEX,
        VALS(bpf_rval), 0x18, NULL, HFILL } },
    { &hf_code_misc_op,
      { "Op", "rpcap.opcode.miscop", FT_UINT16, BASE_HEX,
        VALS(bpf_misc_op), 0xF8, NULL, HFILL } },
    { &hf_jt,
      { "JT", "rpcap.jt", FT_UINT8, BASE_DEC,
        NULL, 0x0, NULL, HFILL } },
    { &hf_jf,
      { "JF", "rpcap.jf", FT_UINT8, BASE_DEC,
        NULL, 0x0, NULL, HFILL } },
    { &hf_instr_value,
      { "Instruction value", "rpcap.instr_value", FT_UINT32, BASE_DEC,
        NULL, 0x0, "Instruction-Dependent value", HFILL } },

    /* Statistics reply */
    { &hf_stats_reply,
      { "Statistics", "rpcap.stats_reply", FT_NONE, BASE_NONE,
        NULL, 0x0, "Statistics reply data", HFILL } },
    { &hf_ifrecv,
      { "Received by kernel filter", "rpcap.ifrecv", FT_UINT32, BASE_DEC,
        NULL, 0x0, "Received by kernel", HFILL } },
    { &hf_ifdrop,
      { "Dropped by network interface", "rpcap.ifdrop", FT_UINT32, BASE_DEC,
        NULL, 0x0, NULL, HFILL } },
    { &hf_krnldrop,
      { "Dropped by kernel filter", "rpcap.krnldrop", FT_UINT32, BASE_DEC,
        NULL, 0x0, NULL, HFILL } },
    { &hf_srvcapt,
      { "Captured by rpcapd", "rpcap.srvcapt", FT_UINT32, BASE_DEC,
        NULL, 0x0, "Captured by RPCAP daemon", HFILL } },

    /* Find all devices reply */
    { &hf_findalldevs_reply,
      { "Find all devices", "rpcap.findalldevs_reply", FT_NONE, BASE_NONE,
        NULL, 0x0, NULL, HFILL } },
    { &hf_findalldevs_if,
      { "Interface", "rpcap.if", FT_NONE, BASE_NONE,
        NULL, 0x0, NULL, HFILL } },
    { &hf_namelen,
      { "Name length", "rpcap.namelen", FT_UINT16, BASE_DEC,
        NULL, 0x0, NULL, HFILL } },
    { &hf_desclen,
      { "Description length", "rpcap.desclen", FT_UINT32, BASE_DEC,
        NULL, 0x0, NULL, HFILL } },
    { &hf_if_flags,
      { "Interface flags", "rpcap.if.flags", FT_UINT32, BASE_DEC,
        NULL, 0x0, NULL, HFILL } },
    { &hf_naddr,
      { "Number of addresses", "rpcap.naddr", FT_UINT32, BASE_DEC,
        NULL, 0x0, NULL, HFILL } },
    { &hf_if_name,
      { "Name", "rpcap.ifname", FT_STRING, BASE_NONE,
        NULL, 0x0, "Interface name", HFILL } },
    { &hf_if_desc,
      { "Description", "rpcap.ifdesc", FT_STRING, BASE_NONE,
        NULL, 0x0, "Interface description", HFILL } },

    /* Find all devices / Interface addresses */
    { &hf_findalldevs_ifaddr,
      { "Interface address", "rpcap.ifaddr", FT_NONE, BASE_NONE,
        NULL, 0x0, NULL, HFILL } },
    { &hf_if_addr,
      { "Address", "rpcap.addr", FT_NONE, BASE_NONE,
        NULL, 0x0, "Network address", HFILL } },
    { &hf_if_netmask,
      { "Netmask", "rpcap.netmask", FT_NONE, BASE_NONE,
        NULL, 0x0, NULL, HFILL } },
    { &hf_if_broadaddr,
      { "Broadcast", "rpcap.broadaddr", FT_NONE, BASE_NONE,
        NULL, 0x0, NULL, HFILL } },
    { &hf_if_dstaddr,
      { "P2P destination address", "rpcap.dstaddr", FT_NONE, BASE_NONE,
        NULL, 0x0, NULL, HFILL } },
    { &hf_if_af,
      { "Address family", "rpcap.if.af", FT_UINT16, BASE_HEX,
        VALS(address_family), 0x0, NULL, HFILL } },
    { &hf_if_port,
      { "Port", "rpcap.if.port", FT_UINT16, BASE_DEC,
        NULL, 0x0, "Port number", HFILL } },
    { &hf_if_ip,
      { "IP address", "rpcap.if.ip", FT_IPv4, BASE_NONE,
        NULL, 0x0, NULL, HFILL } },
    { &hf_if_padding,
      { "Padding", "rpcap.if.padding", FT_BYTES, BASE_NONE,
        NULL, 0x0, NULL, HFILL } },
    { &hf_if_unknown,
      { "Unknown address", "rpcap.if.unknown", FT_BYTES, BASE_NONE,
        NULL, 0x0, NULL, HFILL } },

    /* Sampling request */
    { &hf_sampling_request,
      { "Sampling", "rpcap.sampling_request", FT_NONE, BASE_NONE,
        NULL, 0x0, NULL, HFILL } },
    { &hf_sampling_method,
      { "Method", "rpcap.sampling_method", FT_UINT8, BASE_DEC,
        VALS(sampling_method), 0x0, "Sampling method", HFILL } },
    { &hf_sampling_dummy1,
      { "Dummy1", "rpcap.dummy", FT_UINT8, BASE_DEC,
        NULL, 0x0, NULL, HFILL } },
    { &hf_sampling_dummy2,
      { "Dummy2", "rpcap.dummy", FT_UINT16, BASE_DEC,
        NULL, 0x0, NULL, HFILL } },
    { &hf_sampling_value,
      { "Value", "rpcap.sampling_value", FT_UINT32, BASE_DEC,
        NULL, 0x0, NULL, HFILL } },
  };

  static gint *ett[] = {
    &ett_rpcap,
    &ett_error,
    &ett_packet,
    &ett_auth_request,
    &ett_open_reply,
    &ett_startcap_request,
    &ett_startcap_reply,
    &ett_startcap_flags,
    &ett_filter,
    &ett_filterbpf_insn,
    &ett_filterbpf_insn_code,
    &ett_stats_reply,
    &ett_findalldevs_reply,
    &ett_findalldevs_if,
    &ett_findalldevs_ifaddr,
    &ett_ifaddr,
    &ett_sampling_request
  };

  static ei_register_info ei[] = {
     { &ei_error, { "rpcap.error.expert", PI_SEQUENCE, PI_NOTE, "Error", EXPFILL }},
     { &ei_if_unknown, { "rpcap.if_unknown", PI_SEQUENCE, PI_NOTE, "Unknown address family", EXPFILL }},
     { &ei_no_more_data, { "rpcap.no_more_data", PI_MALFORMED, PI_ERROR, "No more data in packet", EXPFILL }},
     { &ei_caplen_too_big, { "rpcap.caplen_too_big", PI_MALFORMED, PI_ERROR, "Caplen is bigger than the remaining message length", EXPFILL }},
  };

  module_t *rpcap_module;
  expert_module_t* expert_rpcap;

  proto_rpcap = proto_register_protocol (PNAME, PSNAME, PFNAME);
  new_register_dissector (PFNAME, dissect_rpcap, proto_rpcap);
  expert_rpcap = expert_register_protocol(proto_rpcap);
  expert_register_field_array(expert_rpcap, ei, array_length(ei));

  proto_register_field_array (proto_rpcap, hf, array_length (hf));
  proto_register_subtree_array (ett, array_length (ett));

  /* Register our configuration options */
  rpcap_module = prefs_register_protocol (proto_rpcap, proto_reg_handoff_rpcap);

  prefs_register_bool_preference (rpcap_module, "desegment_pdus",
                                  "Reassemble PDUs spanning multiple TCP segments",
                                  "Whether the RPCAP dissector should reassemble PDUs"
                                  " spanning multiple TCP segments."
                                  " To use this option, you must also enable \"Allow subdissectors"
                                  " to reassemble TCP streams\" in the TCP protocol settings.",
                                  &rpcap_desegment);
  prefs_register_bool_preference (rpcap_module, "decode_content",
                                  "Decode content according to link-layer type",
                                  "Whether the packets should be decoded according to"
                                  " the link-layer type.",
                                  &decode_content);
  prefs_register_uint_preference (rpcap_module, "linktype",
                                  "Default link-layer type",
                                  "Default link-layer type to use if an Open Reply packet"
                                  " has not been received.",
                                  10, &global_linktype);
}