Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-nmf.c
blob39bce864170d74893641c6ed90f8377e96db799d
1 /*
2 * packet-nmf.c
4 * Routines for [MC-NMF] .NET Message Framing Protocol
6 * Copyright 2017 Stefan Metzmacher <metze@samba.org>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "config.h"
25 #include <wsutil/str_util.h>
26 #include <epan/packet.h>
27 #include <epan/prefs.h>
28 #include <epan/expert.h>
29 #include <epan/proto_data.h>
30 #include "packet-tcp.h"
31 #include "packet-windows-common.h"
32 #include "packet-gssapi.h"
34 #define NMF_PORT 9389
36 void proto_register_nmf(void);
37 void proto_reg_handoff_nmf(void);
39 static dissector_handle_t gssapi_handle;
40 static dissector_handle_t gssapi_wrap_handle;
42 static dissector_handle_t xml_handle;
44 static int proto_nmf;
46 static int ett_nmf;
47 static int ett_nmf_payload;
49 static int hf_nmf_record;
50 static int hf_nmf_record_type;
51 static int hf_nmf_version_major;
52 static int hf_nmf_version_minor;
53 static int hf_nmf_mode_value;
54 static int hf_nmf_via_length;
55 static int hf_nmf_via_value;
56 static int hf_nmf_known_mode_value;
57 static int hf_nmf_sized_envelope_length;
58 static int hf_nmf_upgrade_length;
59 static int hf_nmf_upgrade_protocol;
60 static int hf_nmf_negotiate_type;
61 static int hf_nmf_negotiate_length;
62 static int hf_nmf_protect_length;
64 static expert_field ei_nmf_bad_record_size;
66 static bool nmf_reassemble = true;
68 enum nmf_record_type {
69 NMF_VERSION_RECORD = 0x00,
70 NMF_MODE_RECORD = 0x01,
71 NMF_VIA_RECORD = 0x02,
72 NMF_KNOWN_ENCODING_RECORD = 0x03,
73 NMF_EXTENSIBLE_ENCODING_RECORD = 0x04,
74 NMF_UNSIZED_ENVELOPE_RECORD = 0x05,
75 NMF_SIZED_ENVELOPE_RECORD = 0x06,
76 NMF_END_RECORD = 0x07,
77 NMF_FAULT_RECORD = 0x08,
78 NMF_UPGRADE_REQUEST_RECORD = 0x09,
79 NMF_UPGRADE_RESPONSE_RECORD = 0x0A,
80 NMF_PREAMBLE_ACK_RECORD = 0x0B,
81 NMF_PREAMBLE_END_RECORD = 0x0C
84 static const value_string record_types[] = {
85 { NMF_VERSION_RECORD, "Version Record"},
86 { NMF_MODE_RECORD, "Mode Record"},
87 { NMF_VIA_RECORD, "Via Record"},
88 { NMF_KNOWN_ENCODING_RECORD, "Known Encoding Record"},
89 { NMF_EXTENSIBLE_ENCODING_RECORD, "Extensible Encoding Record"},
90 { NMF_UNSIZED_ENVELOPE_RECORD, "Unsized Envelope Record"},
91 { NMF_SIZED_ENVELOPE_RECORD, "Sized Envelope Record"},
92 { NMF_END_RECORD, "End Record"},
93 { NMF_FAULT_RECORD, "Fault Record"},
94 { NMF_UPGRADE_REQUEST_RECORD, "Upgrade Request Record"},
95 { NMF_UPGRADE_RESPONSE_RECORD, "Upgrade Response Record"},
96 { NMF_PREAMBLE_ACK_RECORD, "Preamble Ack Record"},
97 { NMF_PREAMBLE_END_RECORD, "Preamble End Record"},
98 { 0, NULL }
101 static const value_string mode_values[] = {
102 { 0x01, "Singleton-Unsized"},
103 { 0x02, "Duplex"},
104 { 0x03, "Simplex"},
105 { 0, NULL }
108 static const value_string known_mode_values[] = {
109 { 0x00, "SOAP 1.1 UTF-8"},
110 { 0x01, "SOAP 1.1 UTF-16"},
111 { 0x02, "SOAP 1.1 Unicode Little-Endian"},
112 { 0x03, "SOAP 1.2 UTF-8"},
113 { 0x04, "SOAP 1.2 UTF-16"},
114 { 0x05, "SOAP 1.2 Unicode Little-Endian"},
115 { 0x06, "SOAP 1.2 MOTM"},
116 { 0x07, "SOAP 1.2 Binary"},
117 { 0x08, "SOAP 1.2 Binary with in-band dictionary"},
118 { 0, NULL }
121 typedef struct nmf_conv_info_t {
122 uint32_t fnum_upgraded;
123 uint32_t fnum_negotiated;
124 } nmf_conv_info_t;
126 /* Read the the varint holding the record size.
127 * Callers MUST check for a 0 return value, which indicates that
128 * parsing the varint failed, to avoid infinite loops.
130 static int
131 dissect_nmf_record_size(tvbuff_t *tvb, proto_tree *tree,
132 int hf_index, int offset, uint32_t *_size)
134 uint64_t size = 0;
135 int start_offset = offset;
137 /* 5 is the encoded size for UINT32_MAX (but can also contain larger
138 * varints).
140 unsigned len = tvb_get_varint(tvb, offset, 5, &size, ENC_VARINT_PROTOBUF);
141 if (len == 0) {
142 proto_tree_add_expert_format(tree, NULL, &ei_nmf_bad_record_size, tvb, offset, 5,
143 "Invalid record size; varint does not end in five bytes");
144 return 0;
146 if (size > UINT32_MAX) {
147 proto_tree_add_expert_format(tree, NULL, &ei_nmf_bad_record_size, tvb, offset, len,
148 "Invalid record size %" PRIu64, size);
149 return 0;
152 if (_size != NULL) {
153 *_size = (uint32_t)size;
156 if (tree != NULL && hf_index != -1) {
157 proto_item *item = NULL;
158 item = proto_tree_add_item(tree, hf_index, tvb,
159 start_offset, -1, ENC_NA);
160 proto_item_set_len(item, (int)len);
161 proto_item_append_text(item, ": %u (0x%x)",
162 (unsigned)size, (unsigned)size);
165 return offset;
168 static int
169 dissect_nmf_record(tvbuff_t *tvb, packet_info *pinfo,
170 nmf_conv_info_t *nmf_info,
171 proto_tree *tree, int offset)
173 proto_item *record_item = NULL;
174 proto_tree *record_tree = NULL;
175 const char *record_name = NULL;
176 enum nmf_record_type record_type;
177 uint32_t size = 0;
178 const uint8_t *str = NULL;
179 tvbuff_t *payload_tvb = NULL;
180 tvbuff_t *xml_tvb = NULL;
182 record_item = proto_tree_add_item(tree, hf_nmf_record, tvb, offset, -1, ENC_NA);
183 proto_item_append_text(record_item, ", start_offset=0x%x, ", (unsigned)offset);
184 record_tree = proto_item_add_subtree(record_item, ett_nmf);
186 record_type = (enum nmf_record_type)tvb_get_uint8(tvb, offset);
187 record_name = val_to_str_const((uint32_t)record_type, record_types,
188 "Unknown Record");
189 proto_tree_add_item(record_tree, hf_nmf_record_type,
190 tvb, offset, 1, ENC_NA);
191 offset += 1;
193 col_append_str(pinfo->cinfo, COL_INFO, record_name);
194 proto_item_append_text(record_item, "%s", record_name);
196 switch (record_type) {
197 case NMF_VERSION_RECORD:
198 proto_tree_add_item(record_tree, hf_nmf_version_major,
199 tvb, offset, 1, ENC_NA);
200 offset += 1;
201 proto_tree_add_item(record_tree, hf_nmf_version_minor,
202 tvb, offset, 1, ENC_NA);
203 offset += 1;
204 break;
205 case NMF_MODE_RECORD:
206 proto_tree_add_item(record_tree, hf_nmf_mode_value,
207 tvb, offset, 1, ENC_NA);
208 offset += 1;
209 break;
210 case NMF_VIA_RECORD:
211 offset = dissect_nmf_record_size(tvb, record_tree,
212 hf_nmf_via_length,
213 offset, &size);
214 if (offset <= 0) {
215 return -1;
218 proto_tree_add_item_ret_string(record_tree, hf_nmf_via_value,
219 tvb, offset, size, ENC_UTF_8,
220 wmem_packet_scope(), &str);
221 offset += size;
222 proto_item_append_text(record_item, ": %s", (const char *)str);
223 break;
224 case NMF_KNOWN_ENCODING_RECORD:
225 proto_tree_add_item(record_tree, hf_nmf_known_mode_value,
226 tvb, offset, 1, ENC_NA);
227 offset += 1;
228 break;
229 case NMF_EXTENSIBLE_ENCODING_RECORD:
230 /* TODO */
231 break;
232 case NMF_UNSIZED_ENVELOPE_RECORD:
233 /* TODO */
234 break;
235 case NMF_SIZED_ENVELOPE_RECORD:
236 offset = dissect_nmf_record_size(tvb, record_tree,
237 hf_nmf_sized_envelope_length,
238 offset, &size);
239 if (offset <= 0) {
240 return -1;
243 payload_tvb = tvb_new_subset_length(tvb, offset, size);
244 offset += size;
245 proto_item_append_text(record_item, ": Payload (%u byte%s)",
246 size, plurality(size, "", "s"));
247 proto_tree_add_format_text(record_tree, payload_tvb, 0, size);
248 #if 0
249 if (0) {
250 /* TODO:
252 * 1. reassemble payload
253 * 2. use
254 * [MC-NBFSE] .NET Binary Format: SOAP Extension
255 * [MC-NBFS] .NET Binary Format: SOAP Data Structure
256 * [MC-NBFX] .NET Binary Format: XML Data Structure
257 * to generate XML
258 * 3. call the XML dissector.
260 if (payload_tvb != NULL) {
261 xml_tvb = NULL;
264 #endif
265 if (xml_tvb != NULL) {
266 call_dissector_with_data(xml_handle, xml_tvb, pinfo,
267 record_tree, NULL);
269 break;
270 case NMF_END_RECORD:
271 /* TODO */
272 break;
273 case NMF_FAULT_RECORD:
274 /* TODO */
275 break;
276 case NMF_UPGRADE_REQUEST_RECORD:
277 offset = dissect_nmf_record_size(tvb, record_tree,
278 hf_nmf_upgrade_length,
279 offset, &size);
280 if (offset <= 0) {
281 return -1;
284 proto_tree_add_item_ret_string(record_tree, hf_nmf_upgrade_protocol,
285 tvb, offset, size, ENC_UTF_8,
286 wmem_packet_scope(), &str);
287 offset += size;
288 proto_item_append_text(record_item, ": %s", (const char *)str);
289 break;
291 case NMF_UPGRADE_RESPONSE_RECORD:
292 nmf_info->fnum_upgraded = pinfo->fd->num;
293 break;
294 case NMF_PREAMBLE_ACK_RECORD:
295 /* TODO */
296 break;
297 case NMF_PREAMBLE_END_RECORD:
298 /* TODO */
299 break;
302 proto_item_append_text(record_item, ", end_offset=0x%x", (unsigned)offset);
303 proto_item_set_end(record_item, tvb, offset);
305 return offset;
308 static unsigned
309 nmf_get_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *_info)
311 nmf_conv_info_t *nmf_info = (nmf_conv_info_t *)_info;
312 enum nmf_record_type record_type;
313 int start_offset = offset;
315 if (pinfo->fd->num > nmf_info->fnum_negotiated) {
316 unsigned remaining = tvb_captured_length_remaining(tvb, offset);
317 unsigned len = 0;
318 unsigned needed = 0;
320 if (remaining < 4) {
321 return 0;
324 len = tvb_get_uint32(tvb, offset, ENC_LITTLE_ENDIAN);
326 needed = 4 + len;
327 return needed;
330 if (pinfo->fd->num > nmf_info->fnum_upgraded) {
331 unsigned remaining = tvb_captured_length_remaining(tvb, offset);
332 unsigned len = 0;
333 unsigned needed = 0;
335 if (remaining < 5) {
336 return 0;
339 offset += 3;
341 len = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
343 needed = 5 + len;
344 return needed;
347 record_type = (enum nmf_record_type)tvb_get_uint8(tvb, offset);
348 offset += 1;
350 switch (record_type) {
351 case NMF_VIA_RECORD:
352 case NMF_SIZED_ENVELOPE_RECORD:
353 case NMF_UPGRADE_REQUEST_RECORD:
355 /* Variable sized record. We must not throw an exception. */
356 uint64_t size = 0;
357 unsigned len = tvb_get_varint(tvb, offset,
358 tvb_captured_length_remaining(tvb, offset),
359 &size, ENC_VARINT_PROTOBUF);
360 /* [MC-NMF] 2.2.2 The record length can be up to UINT32_MAX,
361 * with an encoded size of 5 bytes.
363 if (len == 0) {
364 /* Parsing failed. */
365 if (tvb_captured_length_remaining(tvb, offset) < 5) {
366 /* Fewer than five bytes, so ask for one more segment. */
367 return 0;
370 /* We had at least 5 bytes, so the length is invalid.
371 * Just take the rest of this segment.
372 * The expert info will be handled in the main dissection
373 * routine. */
374 return tvb_reported_length_remaining(tvb, start_offset);
376 if (size > UINT32_MAX) {
377 /* Invalid length */
378 return tvb_reported_length_remaining(tvb, start_offset);
380 offset += (int)len;
381 offset += (int)size;
382 break;
384 case NMF_VERSION_RECORD:
385 offset += 2;
386 break;
387 case NMF_MODE_RECORD:
388 offset += 1;
389 break;
390 case NMF_KNOWN_ENCODING_RECORD:
391 offset += 1;
392 break;
393 case NMF_EXTENSIBLE_ENCODING_RECORD:
394 /* TODO */
395 break;
396 case NMF_UNSIZED_ENVELOPE_RECORD:
397 /* TODO */
398 break;
399 case NMF_END_RECORD:
400 /* TODO */
401 break;
402 case NMF_FAULT_RECORD:
403 /* TODO */
404 break;
405 case NMF_UPGRADE_RESPONSE_RECORD:
406 break;
407 case NMF_PREAMBLE_ACK_RECORD:
408 /* TODO */
409 break;
410 case NMF_PREAMBLE_END_RECORD:
411 /* TODO */
412 break;
415 return offset - start_offset;
418 static int
419 dissect_nmf_payload(tvbuff_t *tvb, packet_info *pinfo,
420 proto_tree *tree, nmf_conv_info_t *nmf_info)
422 int offset = 0;
424 while (tvb_reported_length_remaining(tvb, offset) > 0) {
425 int ret;
427 ret = dissect_nmf_record(tvb, pinfo, nmf_info, tree, offset);
428 if (ret <= 0) {
429 return -1;
431 offset += ret;
434 return offset;
437 static int
438 dissect_nmf_pdu(tvbuff_t *tvb, packet_info *pinfo,
439 proto_tree *tree, void *_info)
441 nmf_conv_info_t *nmf_info = (nmf_conv_info_t *)_info;
443 pinfo->fragmented = true;
445 if (pinfo->fd->num > nmf_info->fnum_negotiated) {
446 proto_item *item = proto_tree_get_parent(tree);
447 uint32_t len = 0;
448 int offset = 0;
449 tvbuff_t *gssapi_tvb = NULL;
450 tvbuff_t *plain_tvb = NULL, *decr_tvb= NULL;
451 int ver_len;
452 gssapi_encrypt_info_t gssapi_encrypt;
454 len = tvb_get_uint32(tvb, offset, ENC_LITTLE_ENDIAN);
455 proto_tree_add_item(tree, hf_nmf_negotiate_length,
456 tvb, offset, 4, ENC_LITTLE_ENDIAN);
457 offset += 4;
459 col_set_str(pinfo->cinfo, COL_INFO, "NMF GSSAPI");
460 col_add_fstr(pinfo->cinfo, COL_INFO,
461 "Protected Packet len: %u (0x%x)",
462 (unsigned)len, (unsigned)len);
463 proto_item_append_text(item, ", Protected Packet len: %u (0x%x)",
464 (unsigned)len, (unsigned)len);
466 gssapi_tvb = tvb_new_subset_length(tvb, offset, len);
467 offset += len;
469 /* Attempt decryption of the GSSAPI wrapped data if possible */
470 memset(&gssapi_encrypt, 0, sizeof(gssapi_encrypt));
471 gssapi_encrypt.decrypt_gssapi_tvb=DECRYPT_GSSAPI_NORMAL;
473 ver_len = call_dissector_with_data(gssapi_wrap_handle, gssapi_tvb,
474 pinfo, tree, &gssapi_encrypt);
475 /* if we could unwrap, do a tvb shuffle */
476 if (gssapi_encrypt.gssapi_decrypted_tvb) {
477 decr_tvb=gssapi_encrypt.gssapi_decrypted_tvb;
478 } else if (gssapi_encrypt.gssapi_wrap_tvb) {
479 plain_tvb=gssapi_encrypt.gssapi_wrap_tvb;
483 * if we don't have unwrapped data,
484 * see if the wrapping involved encryption of the
485 * data; if not, just use the plaintext data.
487 if (!decr_tvb && !plain_tvb) {
488 if(!gssapi_encrypt.gssapi_data_encrypted){
489 plain_tvb = tvb_new_subset_remaining(gssapi_tvb, ver_len);
493 if (decr_tvb) {
494 proto_tree *enc_tree = NULL;
495 unsigned decr_len = tvb_reported_length(decr_tvb);
497 col_set_str(pinfo->cinfo, COL_INFO, "NMF GSS-API Privacy (decrypted): ");
499 if (tree) {
500 enc_tree = proto_tree_add_subtree_format(tree, decr_tvb, 0, -1,
501 ett_nmf_payload, NULL,
502 "GSS-API Encrypted payload (%d byte%s)",
503 decr_len,
504 plurality(decr_len, "", "s"));
506 dissect_nmf_payload(decr_tvb, pinfo, enc_tree, nmf_info);
507 } else if (plain_tvb) {
508 proto_tree *plain_tree = NULL;
509 unsigned plain_len = tvb_reported_length(plain_tvb);
511 col_set_str(pinfo->cinfo, COL_INFO, "NMF GSS-API Integrity: ");
513 if (tree) {
514 plain_tree = proto_tree_add_subtree_format(tree, plain_tvb, 0, -1,
515 ett_nmf_payload, NULL,
516 "GSS-API payload (%d byte%s)",
517 plain_len,
518 plurality(plain_len, "", "s"));
521 dissect_nmf_payload(plain_tvb, pinfo, plain_tree, nmf_info);
522 } else {
523 col_add_fstr(pinfo->cinfo, COL_INFO, "NMF GSS-API Privacy: payload (%d byte%s)",
524 len, plurality(len, "", "s"));
526 proto_tree_add_format_text(tree, gssapi_tvb, 0, len);
528 return offset;
531 if (pinfo->fd->num > nmf_info->fnum_upgraded) {
532 proto_item *item = proto_tree_get_parent(tree);
533 unsigned rlen = tvb_reported_length(tvb);
534 uint16_t len = 0;
535 uint8_t type;
536 int offset = 0;
537 tvbuff_t *negotiate_tvb = NULL;
539 col_set_str(pinfo->cinfo, COL_INFO, "NMF Upgrade");
541 type = tvb_get_uint8(tvb, offset);
542 proto_tree_add_item(tree, hf_nmf_negotiate_type,
543 tvb, offset, 1, ENC_NA);
544 offset += 1;
545 if (type == 0x14) {
546 nmf_info->fnum_negotiated = pinfo->fd->num;
549 offset += 2;
551 len = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
552 proto_tree_add_item(tree, hf_nmf_negotiate_length,
553 tvb, offset, 2, ENC_BIG_ENDIAN);
554 offset += 2;
556 col_add_fstr(pinfo->cinfo, COL_INFO,
557 "Upgraded Packet rlen: %u (0x%x)",
558 (unsigned)rlen, (unsigned)rlen);
559 proto_item_append_text(item, ", Upgraded Packet rlen: %u (0x%x) len: %u (0x%x) type: 0x%02x",
560 (unsigned)rlen, (unsigned)rlen,
561 (unsigned)len, (unsigned)len,
562 (unsigned)type);
563 negotiate_tvb = tvb_new_subset_length(tvb, offset, len);
565 call_dissector(gssapi_handle, negotiate_tvb, pinfo, tree);
566 offset += len;
567 return offset;
570 return dissect_nmf_record(tvb, pinfo, nmf_info, tree, 0);
573 static int
574 dissect_nmf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, _U_ void *_unused)
576 conversation_t *conv = NULL;
577 nmf_conv_info_t *nmf_info = NULL;
578 proto_tree *tree = NULL;
579 proto_item *item = NULL;
581 conv = find_or_create_conversation(pinfo);
582 nmf_info = (nmf_conv_info_t *)conversation_get_proto_data(conv,
583 proto_nmf);
584 if (nmf_info == NULL) {
585 nmf_info = wmem_new0(wmem_file_scope(), nmf_conv_info_t);
586 nmf_info->fnum_upgraded = 0xffffffff;
587 nmf_info->fnum_negotiated = 0xffffffff;
588 conversation_add_proto_data(conv, proto_nmf, nmf_info);
591 col_set_str(pinfo->cinfo, COL_PROTOCOL, "NMF");
592 col_set_str(pinfo->cinfo, COL_INFO, "NMF...");
594 if (parent_tree != NULL) {
595 item = proto_tree_add_item(parent_tree, proto_nmf, tvb, 0, -1, ENC_NA);
596 tree = proto_item_add_subtree(item, ett_nmf);
599 tcp_dissect_pdus(tvb, pinfo, tree, nmf_reassemble,
600 1, /* fixed_length */
601 nmf_get_pdu_len,
602 dissect_nmf_pdu,
603 nmf_info);
604 return tvb_captured_length(tvb);
607 void proto_register_nmf(void)
609 static int *ett[] = {
610 &ett_nmf,
611 &ett_nmf_payload,
613 static hf_register_info hf[] = {
614 { &hf_nmf_record,
615 { "Record", "nmf.record",
616 FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
617 { &hf_nmf_record_type,
618 { "Type", "nmf.type",
619 FT_UINT8, BASE_DEC, VALS(record_types), 0, NULL, HFILL }},
620 { &hf_nmf_version_major,
621 { "Version Major", "nmf.version.major",
622 FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
623 { &hf_nmf_version_minor,
624 { "Version minor", "nmf.version.minor",
625 FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
626 { &hf_nmf_mode_value,
627 { "Mode", "nmf.mode.value",
628 FT_UINT8, BASE_DEC, VALS(mode_values), 0, NULL, HFILL }},
629 { &hf_nmf_via_length,
630 { "Length", "nmf.via.length",
631 FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
632 { &hf_nmf_via_value,
633 { "URI", "nmf.via.uri",
634 FT_STRING, BASE_NONE, NULL, 0x0, "Via URI", HFILL }},
635 { &hf_nmf_known_mode_value,
636 { "Mode", "nmf.known_mode.value",
637 FT_UINT8, BASE_DEC, VALS(known_mode_values), 0, NULL, HFILL }},
638 { &hf_nmf_sized_envelope_length,
639 { "Length", "nmf.sized_envelope.length",
640 FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
641 { &hf_nmf_upgrade_length,
642 { "Length", "nmf.upgrade.length",
643 FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
644 { &hf_nmf_upgrade_protocol,
645 { "Upgrade Protocol", "nmf.upgrade.protocol",
646 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
647 { &hf_nmf_negotiate_type,
648 { "Negotiate Type", "nmf.negotiate.type",
649 FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
650 { &hf_nmf_negotiate_length,
651 { "Negotiate Length", "nmf.negotiate.length",
652 FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
653 { &hf_nmf_protect_length,
654 { "Protect Length", "nmf.protect.length",
655 FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
657 module_t *nmf_module = NULL;
659 proto_nmf = proto_register_protocol("NMF (.NET Message Framing Protocol)",
660 "NMF", "nmf");
661 proto_register_subtree_array(ett, array_length(ett));
662 proto_register_field_array(proto_nmf, hf, array_length(hf));
664 nmf_module = prefs_register_protocol(proto_nmf, NULL);
666 expert_module_t *expert_nmf;
667 static ei_register_info ei[] = {
668 { &ei_nmf_bad_record_size,
669 { "nmf.bad_record_size", PI_MALFORMED, PI_WARN, "Invalid record size varint", EXPFILL }},
672 expert_nmf = expert_register_protocol(proto_nmf);
673 expert_register_field_array(expert_nmf, ei, array_length(ei));
675 prefs_register_bool_preference(nmf_module,
676 "reassemble_nmf",
677 "Reassemble NMF fragments",
678 "Whether the NMF dissector should reassemble fragmented payloads",
679 &nmf_reassemble);
683 void
684 proto_reg_handoff_nmf(void)
686 dissector_handle_t nmf_handle;
688 nmf_handle = create_dissector_handle(dissect_nmf, proto_nmf);
689 dissector_add_uint_with_preference("tcp.port", NMF_PORT, nmf_handle);
691 gssapi_handle = find_dissector_add_dependency("gssapi", proto_nmf);
692 gssapi_wrap_handle = find_dissector_add_dependency("gssapi_verf", proto_nmf);
694 xml_handle = find_dissector_add_dependency("xml", proto_nmf);