HACK: pinfo->private_data points to smb_info again
[wireshark-wip.git] / epan / dissectors / packet-winsrepl.c
blob8ebd17bd4889cdaf0c5f154176bd4ad5922ff466
1 /*
2 * packet-winsrepl.c
4 * Routines for WINS Replication packet dissection
6 * Copyright 2005 Stefan Metzmacher <metze@samba.org>
8 * $Id$
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1998 Gerald Combs
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 #include "config.h"
31 #include <time.h>
32 #include <glib.h>
33 #include <ctype.h>
35 #include <epan/packet.h>
36 #include <epan/exceptions.h>
37 #include <epan/prefs.h>
38 #include <epan/tap.h>
40 #include "packet-windows-common.h"
41 #include "packet-netbios.h"
43 #include "packet-tcp.h"
45 static gboolean winsrepl_reassemble = TRUE;
47 static int proto_winsrepl = -1;
49 static int hf_winsrepl_size = -1;
50 static int hf_winsrepl_opcode = -1;
51 static int hf_winsrepl_assoc_ctx = -1;
52 static int hf_winsrepl_mess_type = -1;
54 static int hf_winsrepl_start_minor_version = -1;
55 static int hf_winsrepl_start_major_version = -1;
57 static int hf_winsrepl_stop_reason = -1;
59 static int hf_winsrepl_replication_command = -1;
61 static int hf_winsrepl_owner_address = -1;
62 static int hf_winsrepl_owner_max_version = -1;
63 static int hf_winsrepl_owner_min_version = -1;
64 static int hf_winsrepl_owner_type = -1;
66 static int hf_winsrepl_table_partner_count = -1;
67 static int hf_winsrepl_table_initiator = -1;
69 static int hf_winsrepl_ip_owner = -1;
70 static int hf_winsrepl_ip_ip = -1;
71 static int hf_winsrepl_addr_list_num_ips = -1;
73 static int hf_winsrepl_name_len = -1;
74 static int hf_winsrepl_name_flags = -1;
75 static int hf_winsrepl_name_flags_rectype = -1;
76 static int hf_winsrepl_name_flags_recstate = -1;
77 static int hf_winsrepl_name_flags_local = -1;
78 static int hf_winsrepl_name_flags_hosttype = -1;
79 static int hf_winsrepl_name_flags_static = -1;
80 static int hf_winsrepl_name_group_flag = -1;
81 static int hf_winsrepl_name_version_id = -1;
82 static int hf_winsrepl_name_unknown = -1;
84 static int hf_winsrepl_reply_num_names = -1;
86 static gint ett_winsrepl = -1;
88 static gint ett_winsrepl_start = -1;
89 static gint ett_winsrepl_stop = -1;
90 static gint ett_winsrepl_replication = -1;
92 static gint ett_winsrepl_owner = -1;
93 static gint ett_winsrepl_table_reply = -1;
95 static gint ett_winsrepl_ip = -1;
96 static gint ett_winsrepl_addr_list = -1;
98 static gint ett_winsrepl_name = -1;
99 static gint ett_winsrepl_send_reply = -1;
101 static gint ett_winsrepl_flags = -1;
103 #define WINS_REPLICATION_PORT ( 42 )
104 #define WREPL_OPCODE_BITS ( 0x7800 )
106 enum wrepl_replication_cmd {
107 WREPL_REPL_TABLE_QUERY=0,
108 WREPL_REPL_TABLE_REPLY=1,
109 WREPL_REPL_SEND_REQUEST=2,
110 WREPL_REPL_SEND_REPLY=3,
111 WREPL_REPL_UPDATE=4,
112 WREPL_REPL_UPDATE2=5,
113 WREPL_REPL_INFORM=8,
114 WREPL_REPL_INFORM2=9
117 enum wrepl_mess_type {
118 WREPL_START_ASSOCIATION=0,
119 WREPL_START_ASSOCIATION_REPLY=1,
120 WREPL_STOP_ASSOCIATION=2,
121 WREPL_REPLICATION=3
124 static unsigned int glb_winsrepl_tcp_port = WINS_REPLICATION_PORT;
126 static const value_string replication_cmd_vals[] = {
127 {WREPL_REPL_TABLE_QUERY, "WREPL_REPL_TABLE_QUERY"},
128 {WREPL_REPL_TABLE_REPLY, "WREPL_REPL_TABLE_REPLY"},
129 {WREPL_REPL_SEND_REQUEST, "WREPL_REPL_SEND_REQUEST"},
130 {WREPL_REPL_SEND_REPLY, "WREPL_REPL_SEND_REPLY"},
131 {WREPL_REPL_UPDATE, "WREPL_REPL_UPDATE"},
132 {WREPL_REPL_UPDATE2, "WREPL_REPL_UPDATE2"},
133 {WREPL_REPL_INFORM, "WREPL_REPL_INFORM"},
134 {WREPL_REPL_INFORM2, "WREPL_REPL_INFORM2"},
135 {0, NULL}
138 static const value_string message_type_vals[] = {
139 {WREPL_START_ASSOCIATION, "WREPL_START_ASSOCIATION"},
140 {WREPL_START_ASSOCIATION_REPLY, "WREPL_START_ASSOCIATION_REPLY"},
141 {WREPL_STOP_ASSOCIATION, "WREPL_STOP_ASSOCIATION"},
142 {WREPL_REPLICATION, "WREPL_REPLICATION"},
143 {0, NULL}
146 #define WREPL_NAME_TYPE_MASK 0x03
148 #define WREPL_NAME_TYPE_UNIQUE 0x00
149 #define WREPL_NAME_TYPE_NORMAL_GROUP 0x01
150 #define WREPL_NAME_TYPE_SPECIAL_GROUP 0x02
151 #define WREPL_NAME_TYPE_MULTIHOMED 0x03
153 static const value_string rectype_vals[] = {
154 {WREPL_NAME_TYPE_UNIQUE, "Unique"},
155 {WREPL_NAME_TYPE_NORMAL_GROUP, "Normal group"},
156 {WREPL_NAME_TYPE_SPECIAL_GROUP, "Special group"},
157 {WREPL_NAME_TYPE_MULTIHOMED, "Multihomed"},
158 {0, NULL}
161 static const value_string recstate_vals[] = {
162 {0x00, "Active"},
163 {0x01, "Released"},
164 {0x02, "Tombstoned"},
165 {0x03, "Deleted"},
166 {0, NULL}
169 static const value_string hosttype_vals[] = {
170 {0x00, "B-node"},
171 {0x01, "P-node"},
172 {0x02, "M-node"},
173 {0x03, "H-node"},
174 {0, NULL}
177 static int
178 dissect_winsrepl_start(tvbuff_t *winsrepl_tvb, _U_ packet_info *pinfo,
179 int winsrepl_offset, proto_tree *winsrepl_tree)
181 proto_item *start_item = NULL;
182 proto_tree *start_tree = NULL;
184 if (winsrepl_tree) {
185 start_item = proto_tree_add_text(winsrepl_tree, winsrepl_tvb, winsrepl_offset, -1 , "WREPL_START_ASSOCIATION");
186 start_tree = proto_item_add_subtree(start_item, ett_winsrepl_start);
189 /* ASSOC_CTX */
190 proto_tree_add_item(start_tree, hf_winsrepl_assoc_ctx, winsrepl_tvb, winsrepl_offset, 4, ENC_BIG_ENDIAN);
191 winsrepl_offset += 4;
193 /* MINOR VERSION */
194 proto_tree_add_item(start_tree, hf_winsrepl_start_minor_version, winsrepl_tvb, winsrepl_offset, 2, ENC_BIG_ENDIAN);
195 winsrepl_offset += 2;
197 /* MAJOR VERSION */
198 proto_tree_add_item(start_tree, hf_winsrepl_start_major_version, winsrepl_tvb, winsrepl_offset, 2, ENC_BIG_ENDIAN);
199 winsrepl_offset += 2;
201 return winsrepl_offset;
204 static int
205 dissect_winsrepl_stop(tvbuff_t *winsrepl_tvb, _U_ packet_info *pinfo,
206 int winsrepl_offset, proto_tree *winsrepl_tree)
208 guint32 reason;
209 proto_item *stop_item = NULL;
210 proto_tree *stop_tree = NULL;
212 if (winsrepl_tree) {
213 stop_item = proto_tree_add_text(winsrepl_tree, winsrepl_tvb, winsrepl_offset, -1 , "WREPL_STOP_ASSOCIATION");
214 stop_tree = proto_item_add_subtree(stop_item, ett_winsrepl_stop);
217 /* REASON */
218 reason = tvb_get_ntohl(winsrepl_tvb, winsrepl_offset);
219 proto_tree_add_uint(stop_tree, hf_winsrepl_stop_reason, winsrepl_tvb, winsrepl_offset, 4, reason);
220 winsrepl_offset += 4;
222 proto_item_append_text(stop_item, ", Reason: 0x%08X", reason);
224 return winsrepl_offset;
227 static int
228 dissect_winsrepl_table_query(tvbuff_t *winsrepl_tvb _U_, packet_info *pinfo _U_,
229 int winsrepl_offset, proto_tree *winsrepl_tree _U_)
231 /* Nothing to do here */
232 return winsrepl_offset;
235 static int
236 dissect_winsrepl_wins_owner(tvbuff_t *winsrepl_tvb, _U_ packet_info *pinfo,
237 int winsrepl_offset, proto_tree *winsrepl_tree,
238 proto_tree *sub_tree, guint32 idx)
240 proto_item *owner_item = NULL;
241 proto_tree *owner_tree = NULL;
243 if (sub_tree) {
244 owner_item = proto_tree_add_text(sub_tree, winsrepl_tvb, winsrepl_offset, 24 , "WINS Owner [%u]", idx);
245 owner_tree = proto_item_add_subtree(owner_item, ett_winsrepl_owner);
246 } else if (winsrepl_tree) {
247 owner_item = proto_tree_add_text(winsrepl_tree, winsrepl_tvb, winsrepl_offset, 24 , "WINS Owner");
248 owner_tree = proto_item_add_subtree(owner_item, ett_winsrepl_owner);
251 /* ADDRESS */
252 proto_tree_add_item(owner_tree, hf_winsrepl_owner_address, winsrepl_tvb, winsrepl_offset, 4, ENC_BIG_ENDIAN);
253 winsrepl_offset += 4;
255 /* MAX_VERSION */
256 proto_tree_add_item(owner_tree, hf_winsrepl_owner_max_version, winsrepl_tvb, winsrepl_offset, 8, ENC_BIG_ENDIAN);
257 winsrepl_offset += 8;
259 /* MIN_VERSION */
260 proto_tree_add_item(owner_tree, hf_winsrepl_owner_min_version, winsrepl_tvb, winsrepl_offset, 8, ENC_BIG_ENDIAN);
261 winsrepl_offset += 8;
263 /* TYPE */
264 proto_tree_add_item(owner_tree, hf_winsrepl_owner_type, winsrepl_tvb, winsrepl_offset, 4, ENC_BIG_ENDIAN);
265 winsrepl_offset += 4;
267 return winsrepl_offset;
270 static int
271 dissect_winsrepl_table_reply(tvbuff_t *winsrepl_tvb, packet_info *pinfo,
272 int winsrepl_offset, proto_tree *winsrepl_tree)
274 proto_item *table_item = NULL;
275 proto_tree *table_tree = NULL;
276 guint32 partner_count;
277 guint32 i;
279 if (winsrepl_tree) {
280 table_item = proto_tree_add_text(winsrepl_tree, winsrepl_tvb, winsrepl_offset, -1 , "WREPL_REPL_TABLE_REPLY");
281 table_tree = proto_item_add_subtree(table_item, ett_winsrepl_table_reply);
284 /* PARTNER COUNT */
285 partner_count = tvb_get_ntohl(winsrepl_tvb, winsrepl_offset);
286 proto_tree_add_uint(table_tree, hf_winsrepl_table_partner_count, winsrepl_tvb, winsrepl_offset, 4, partner_count);
287 winsrepl_offset += 4;
289 for (i=0; i < partner_count; i++) {
290 winsrepl_offset = dissect_winsrepl_wins_owner(winsrepl_tvb, pinfo,
291 winsrepl_offset, table_tree,
292 table_tree, i);
295 /* INITIATOR */
296 proto_tree_add_item(table_tree, hf_winsrepl_table_initiator, winsrepl_tvb, winsrepl_offset, 4, ENC_BIG_ENDIAN);
297 winsrepl_offset += 4;
299 return winsrepl_offset;
302 static int
303 dissect_winsrepl_send_request(tvbuff_t *winsrepl_tvb, packet_info *pinfo,
304 int winsrepl_offset, proto_tree *winsrepl_tree)
306 winsrepl_offset = dissect_winsrepl_wins_owner(winsrepl_tvb, pinfo,
307 winsrepl_offset, winsrepl_tree,
308 NULL, 0);
310 return winsrepl_offset;
313 static int
314 dissect_winsrepl_wins_ip(tvbuff_t *winsrepl_tvb, _U_ packet_info *pinfo,
315 int winsrepl_offset, proto_tree *winsrepl_tree,
316 guint32 *addr, proto_tree *sub_tree, guint32 idx)
318 proto_item *ip_item = NULL;
319 proto_tree *ip_tree = NULL;
321 if (sub_tree) {
322 ip_item = proto_tree_add_text(sub_tree, winsrepl_tvb, winsrepl_offset, 8 , "WINS IP [%u]", idx);
323 ip_tree = proto_item_add_subtree(ip_item, ett_winsrepl_ip);
324 } else if (winsrepl_tree) {
325 ip_item = proto_tree_add_text(winsrepl_tree, winsrepl_tvb, winsrepl_offset, 8 , "WINS IP");
326 ip_tree = proto_item_add_subtree(ip_item, ett_winsrepl_ip);
329 /* OWNER */
330 proto_tree_add_item(ip_tree, hf_winsrepl_ip_owner, winsrepl_tvb, winsrepl_offset, 4, ENC_BIG_ENDIAN);
331 winsrepl_offset += 4;
333 /* IP */
334 *addr = tvb_get_ipv4(winsrepl_tvb, winsrepl_offset);
335 proto_tree_add_ipv4(ip_tree, hf_winsrepl_ip_ip, winsrepl_tvb, winsrepl_offset, 4, *addr);
336 proto_item_append_text(ip_item, ": %s", ip_to_str((guint8 *)addr));
337 winsrepl_offset += 4;
339 return winsrepl_offset;
342 static int
343 dissect_winsrepl_wins_address_list(tvbuff_t *winsrepl_tvb, packet_info *pinfo,
344 int winsrepl_offset, proto_tree *winsrepl_tree,
345 proto_item *parent_item)
347 proto_item *addr_list_item = NULL;
348 proto_tree *addr_list_tree = NULL;
349 int old_offset = winsrepl_offset;
350 guint32 num_ips;
351 guint32 ip;
352 guint32 i;
354 if (winsrepl_tree) {
355 addr_list_item = proto_tree_add_text(winsrepl_tree, winsrepl_tvb, winsrepl_offset, -1 , "WINS Address List");
356 addr_list_tree = proto_item_add_subtree(addr_list_item, ett_winsrepl_addr_list);
359 /* NUM_IPS */
360 num_ips = tvb_get_letohl(winsrepl_tvb, winsrepl_offset);
361 proto_tree_add_uint(addr_list_tree, hf_winsrepl_addr_list_num_ips, winsrepl_tvb, winsrepl_offset, 4, num_ips);
362 winsrepl_offset += 4;
364 for (i=0; i < num_ips; i++) {
365 winsrepl_offset = dissect_winsrepl_wins_ip(winsrepl_tvb, pinfo,
366 winsrepl_offset, addr_list_tree,
367 &ip, addr_list_tree, i);
368 if (i == 0) {
369 proto_item_append_text(parent_item, ": %s", ip_to_str((guint8 *)&ip));
370 proto_item_append_text(addr_list_item, ": %s", ip_to_str((guint8 *)&ip));
371 } else {
372 proto_item_append_text(parent_item, ", %s", ip_to_str((guint8 *)&ip));
373 proto_item_append_text(addr_list_item, ", %s", ip_to_str((guint8 *)&ip));
377 proto_item_set_len(addr_list_item, winsrepl_offset - old_offset);
379 return winsrepl_offset;
382 static int
383 dissect_winsrepl_wins_name(tvbuff_t *winsrepl_tvb, packet_info *pinfo,
384 int winsrepl_offset, proto_tree *winsrepl_tree,
385 proto_tree *sub_tree, guint32 idx)
387 proto_item *name_item = NULL;
388 proto_tree *name_tree = NULL;
389 proto_item *flags_item;
390 proto_tree *flags_tree;
391 int old_offset = winsrepl_offset;
392 tvbuff_t *name_tvb = NULL;
393 guint32 name_len;
394 char name_str[(NETBIOS_NAME_LEN - 1)*4 + 1];
395 int name_type;
396 guint32 flags;
397 guint32 addr;
399 if (sub_tree) {
400 name_item = proto_tree_add_text(sub_tree, winsrepl_tvb, winsrepl_offset, -1 , "WINS Name [%u]", idx);
401 name_tree = proto_item_add_subtree(name_item, ett_winsrepl_name);
402 } else if (winsrepl_tree) {
403 name_item = proto_tree_add_text(winsrepl_tree, winsrepl_tvb, winsrepl_offset, -1 , "WINS Name");
404 name_tree = proto_item_add_subtree(name_item, ett_winsrepl_name);
407 /* NAME_LEN */
408 name_len = tvb_get_ntohl(winsrepl_tvb, winsrepl_offset);
409 if ((gint) name_len < 1) {
410 proto_tree_add_text(name_tree, winsrepl_tvb, winsrepl_offset,
411 4, "Bad name length: %u", name_len);
412 THROW(ReportedBoundsError);
414 proto_tree_add_uint(name_tree, hf_winsrepl_name_len, winsrepl_tvb, winsrepl_offset, 4, name_len);
415 winsrepl_offset += 4;
417 /* NAME: TODO! */
419 * XXX - apparently, according to the Samba code for handling
420 * WINS replication, there's a bug in a lot of versions of Windows,
421 * including W2K SP2, wherein the first and last bytes of the
422 * name (the last byte being the name type) are swapped if
423 * the type is 0x1b. I think I've seen this in at least
424 * one capture.
426 name_tvb = tvb_new_subset(winsrepl_tvb, winsrepl_offset, name_len, name_len);
427 netbios_add_name("Name", name_tvb, 0, name_tree);
428 name_type = get_netbios_name(name_tvb, 0, name_str, (NETBIOS_NAME_LEN - 1)*4 + 1);
429 proto_item_append_text(name_item, ": %s<%02x>", name_str, name_type);
430 winsrepl_offset += name_len;
432 /* ALIGN to 4 Byte */
433 /* winsrepl_offset += ((winsrepl_offset & (4-1)) == 0 ? 0 : (4 - (winsrepl_offset & (4-1)))); */
434 /* Windows including w2k8 add 4 padding bytes, when it's already 4 byte
435 * alligned... This happens when the name has a "scope" part
437 winsrepl_offset += 4 - (winsrepl_offset & (4-1));
439 /* FLAGS */
441 * XXX - there appear to be more flag bits, but I didn't see
442 * anything in the Samba code about them.
444 flags = tvb_get_ntohl(winsrepl_tvb, winsrepl_offset);
445 flags_item = proto_tree_add_uint(name_tree, hf_winsrepl_name_flags, winsrepl_tvb, winsrepl_offset, 4, flags);
446 flags_tree = proto_item_add_subtree(flags_item, ett_winsrepl_flags);
447 proto_tree_add_uint(flags_tree, hf_winsrepl_name_flags_rectype, winsrepl_tvb, winsrepl_offset, 4, flags);
448 proto_tree_add_uint(flags_tree, hf_winsrepl_name_flags_recstate, winsrepl_tvb, winsrepl_offset, 4, flags);
449 proto_tree_add_boolean(flags_tree, hf_winsrepl_name_flags_local, winsrepl_tvb, winsrepl_offset, 4, flags);
450 proto_tree_add_uint(flags_tree, hf_winsrepl_name_flags_hosttype, winsrepl_tvb, winsrepl_offset, 4, flags);
451 proto_tree_add_boolean(flags_tree, hf_winsrepl_name_flags_static, winsrepl_tvb, winsrepl_offset, 4, flags);
452 winsrepl_offset += 4;
454 /* GROUP_FLAG */
455 /* XXX - is this just a Boolean? */
456 proto_tree_add_item(name_tree, hf_winsrepl_name_group_flag, winsrepl_tvb, winsrepl_offset, 4, ENC_LITTLE_ENDIAN);
457 winsrepl_offset += 4;
459 /* Version ID */
460 proto_tree_add_item(name_tree, hf_winsrepl_name_version_id, winsrepl_tvb, winsrepl_offset, 8, ENC_BIG_ENDIAN);
461 winsrepl_offset += 8;
463 switch (flags & WREPL_NAME_TYPE_MASK) {
465 case WREPL_NAME_TYPE_UNIQUE:
466 case WREPL_NAME_TYPE_NORMAL_GROUP:
467 /* Single address */
468 addr = tvb_get_ipv4(winsrepl_tvb, winsrepl_offset);
469 proto_tree_add_ipv4(name_tree, hf_winsrepl_ip_ip, winsrepl_tvb, winsrepl_offset, 4, addr);
470 proto_item_append_text(name_item, ": %s", ip_to_str((guint8 *)&addr));
471 winsrepl_offset += 4;
472 break;
474 case WREPL_NAME_TYPE_SPECIAL_GROUP:
475 case WREPL_NAME_TYPE_MULTIHOMED:
476 /* Address list */
477 winsrepl_offset = dissect_winsrepl_wins_address_list(winsrepl_tvb, pinfo,
478 winsrepl_offset, name_tree,
479 name_item);
480 break;
483 /* UNKNOWN, little or big endian??? */
484 proto_tree_add_item(name_tree, hf_winsrepl_name_unknown, winsrepl_tvb, winsrepl_offset, 4, ENC_BIG_ENDIAN);
485 winsrepl_offset += 4;
487 proto_item_set_len(name_item, winsrepl_offset - old_offset);
489 return winsrepl_offset;
492 static int
493 dissect_winsrepl_send_reply(tvbuff_t *winsrepl_tvb, packet_info *pinfo,
494 int winsrepl_offset, proto_tree *winsrepl_tree)
496 proto_item *rep_item = NULL;
497 proto_tree *rep_tree = NULL;
498 guint32 num_names;
499 guint32 i;
501 if (winsrepl_tree) {
502 rep_item = proto_tree_add_text(winsrepl_tree, winsrepl_tvb, winsrepl_offset, -1 , "WREPL_REPL_SEND_REPLY");
503 rep_tree = proto_item_add_subtree(rep_item, ett_winsrepl_send_reply);
506 /* NUM NAMES */
507 num_names = tvb_get_ntohl(winsrepl_tvb, winsrepl_offset);
508 proto_tree_add_uint(rep_tree, hf_winsrepl_reply_num_names, winsrepl_tvb, winsrepl_offset, 4, num_names);
509 winsrepl_offset += 4;
511 for (i=0; i < num_names; i++) {
512 winsrepl_offset = dissect_winsrepl_wins_name(winsrepl_tvb, pinfo,
513 winsrepl_offset, rep_tree,
514 rep_tree, i);
517 return winsrepl_offset;
520 static int
521 dissect_winsrepl_update(tvbuff_t *winsrepl_tvb, packet_info *pinfo,
522 int winsrepl_offset, proto_tree *winsrepl_tree)
524 winsrepl_offset = dissect_winsrepl_table_reply(winsrepl_tvb, pinfo,
525 winsrepl_offset, winsrepl_tree);
526 return winsrepl_offset;
529 static int
530 dissect_winsrepl_update2(tvbuff_t *winsrepl_tvb, packet_info *pinfo,
531 int winsrepl_offset, proto_tree *winsrepl_tree)
533 winsrepl_offset = dissect_winsrepl_table_reply(winsrepl_tvb, pinfo,
534 winsrepl_offset, winsrepl_tree);
535 return winsrepl_offset;
538 static int
539 dissect_winsrepl_inform(tvbuff_t *winsrepl_tvb, packet_info *pinfo,
540 int winsrepl_offset, proto_tree *winsrepl_tree)
542 winsrepl_offset = dissect_winsrepl_table_reply(winsrepl_tvb, pinfo,
543 winsrepl_offset, winsrepl_tree);
544 return winsrepl_offset;
547 static int
548 dissect_winsrepl_inform2(tvbuff_t *winsrepl_tvb, packet_info *pinfo,
549 int winsrepl_offset, proto_tree *winsrepl_tree)
551 winsrepl_offset = dissect_winsrepl_table_reply(winsrepl_tvb, pinfo,
552 winsrepl_offset, winsrepl_tree);
553 return winsrepl_offset;
556 static int
557 dissect_winsrepl_replication(tvbuff_t *winsrepl_tvb, packet_info *pinfo,
558 int winsrepl_offset, proto_item *winsrepl_item, proto_tree *winsrepl_tree)
560 proto_item *repl_item = NULL;
561 proto_tree *repl_tree = NULL;
562 enum wrepl_replication_cmd command;
564 if (winsrepl_tree) {
565 repl_item = proto_tree_add_text(winsrepl_tree, winsrepl_tvb, winsrepl_offset, -1 , "WREPL_REPLICATION");
566 repl_tree = proto_item_add_subtree(repl_item, ett_winsrepl_replication);
569 /* REPLIICATION_CMD */
570 command = (enum wrepl_replication_cmd)tvb_get_ntohl(winsrepl_tvb, winsrepl_offset);
571 proto_tree_add_uint(repl_tree, hf_winsrepl_replication_command, winsrepl_tvb, winsrepl_offset, 4, command);
572 winsrepl_offset += 4;
574 switch (command) {
575 case WREPL_REPL_TABLE_QUERY:
576 col_set_str(pinfo->cinfo, COL_INFO, "WREPL_REPL_TABLE_QUERY");
577 proto_item_append_text(winsrepl_item, ", WREPL_REPL_TABLE_QUERY");
578 proto_item_append_text(repl_item, ", WREPL_REPL_TABLE_QUERY");
579 winsrepl_offset = dissect_winsrepl_table_query(winsrepl_tvb, pinfo,
580 winsrepl_offset, repl_tree);
581 break;
582 case WREPL_REPL_TABLE_REPLY:
583 col_set_str(pinfo->cinfo, COL_INFO, "WREPL_REPL_TABLE_REPLY");
584 proto_item_append_text(winsrepl_item, ", WREPL_REPL_TABLE_REPLY");
585 proto_item_append_text(repl_item, ", WREPL_REPL_TABLE_REPLY");
586 winsrepl_offset = dissect_winsrepl_table_reply(winsrepl_tvb, pinfo,
587 winsrepl_offset, repl_tree);
588 break;
589 case WREPL_REPL_SEND_REQUEST:
590 col_set_str(pinfo->cinfo, COL_INFO, "WREPL_REPL_SEND_REQUEST");
591 proto_item_append_text(winsrepl_item, ", WREPL_REPL_SEND_REQUEST");
592 proto_item_append_text(repl_item, ", WREPL_REPL_SEND_REQUEST");
593 winsrepl_offset = dissect_winsrepl_send_request(winsrepl_tvb, pinfo,
594 winsrepl_offset, repl_tree);
595 break;
596 case WREPL_REPL_SEND_REPLY:
597 col_set_str(pinfo->cinfo, COL_INFO, "WREPL_REPL_SEND_REPLY");
598 proto_item_append_text(winsrepl_item, ", WREPL_REPL_SEND_REPLY");
599 proto_item_append_text(repl_item, ", WREPL_REPL_SEND_REPLY");
600 winsrepl_offset = dissect_winsrepl_send_reply(winsrepl_tvb, pinfo,
601 winsrepl_offset, repl_tree);
602 break;
603 case WREPL_REPL_UPDATE:
604 col_set_str(pinfo->cinfo, COL_INFO, "WREPL_REPL_UPDATE");
605 proto_item_append_text(winsrepl_item, ", WREPL_REPL_UPDATE");
606 proto_item_append_text(repl_item, ", WREPL_REPL_UPDATE");
607 winsrepl_offset = dissect_winsrepl_update(winsrepl_tvb, pinfo,
608 winsrepl_offset, repl_tree);
609 break;
610 case WREPL_REPL_UPDATE2:
611 col_set_str(pinfo->cinfo, COL_INFO, "WREPL_REPL_UPDATE2");
612 proto_item_append_text(winsrepl_item, ",WREPL_REPL_UPDATE2");
613 proto_item_append_text(repl_item, ",WREPL_REPL_UPDATE2");
614 winsrepl_offset = dissect_winsrepl_update2(winsrepl_tvb, pinfo,
615 winsrepl_offset, repl_tree);
616 break;
617 case WREPL_REPL_INFORM:
618 col_set_str(pinfo->cinfo, COL_INFO, "WREPL_REPL_INFORM");
619 proto_item_append_text(winsrepl_item, ", WREPL_REPL_INFORM");
620 proto_item_append_text(repl_item, ", WREPL_REPL_INFORM");
621 winsrepl_offset = dissect_winsrepl_inform(winsrepl_tvb, pinfo,
622 winsrepl_offset, repl_tree);
623 break;
624 case WREPL_REPL_INFORM2:
625 col_set_str(pinfo->cinfo, COL_INFO, "WREPL_REPL_INFORM2");
626 proto_item_append_text(winsrepl_item, ", WREPL_REPL_INFORM2");
627 proto_item_append_text(repl_item, ", WREPL_REPL_INFORM2");
628 winsrepl_offset = dissect_winsrepl_inform2(winsrepl_tvb, pinfo,
629 winsrepl_offset, repl_tree);
630 break;
633 return winsrepl_offset;
636 static int
637 dissect_winsrepl_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data _U_)
639 int offset = 0;
640 proto_item *winsrepl_item;
641 proto_tree *winsrepl_tree;
642 enum wrepl_mess_type mess_type;
644 col_set_str(pinfo->cinfo, COL_PROTOCOL, "WINS-Replication");
645 col_clear(pinfo->cinfo, COL_INFO);
647 winsrepl_item = proto_tree_add_item(parent_tree, proto_winsrepl, tvb, offset, -1, ENC_NA);
648 winsrepl_tree = proto_item_add_subtree(winsrepl_item, ett_winsrepl);
650 /* SIZE */
651 proto_tree_add_item(winsrepl_tree, hf_winsrepl_size, tvb, offset, 4, ENC_BIG_ENDIAN);
652 offset += 4;
654 /* OPCODE */
655 proto_tree_add_item(winsrepl_tree, hf_winsrepl_opcode, tvb, offset, 4, ENC_BIG_ENDIAN);
656 offset += 4;
658 /* ASSOC_CTX */
659 proto_tree_add_item(winsrepl_tree, hf_winsrepl_assoc_ctx, tvb, offset, 4, ENC_BIG_ENDIAN);
660 offset += 4;
662 /* MESSAGE_TYPE */
663 mess_type = (enum wrepl_mess_type)tvb_get_ntohl(tvb, offset);
664 proto_tree_add_uint(winsrepl_tree, hf_winsrepl_mess_type, tvb, offset, 4, mess_type);
665 offset += 4;
667 switch (mess_type) {
668 case WREPL_START_ASSOCIATION:
669 col_set_str(pinfo->cinfo, COL_INFO, "WREPL_START_ASSOCIATION");
670 proto_item_append_text(winsrepl_item, ", WREPL_START_ASSOCIATION");
671 dissect_winsrepl_start(tvb, pinfo,
672 offset, winsrepl_tree);
673 break;
674 case WREPL_START_ASSOCIATION_REPLY:
675 col_set_str(pinfo->cinfo, COL_INFO, "WREPL_START_ASSOCIATION_REPLY");
676 proto_item_append_text(winsrepl_item, ", WREPL_START_ASSOCIATION_REPLY");
677 dissect_winsrepl_start(tvb, pinfo,
678 offset, winsrepl_tree);
679 break;
680 case WREPL_STOP_ASSOCIATION:
681 col_set_str(pinfo->cinfo, COL_INFO, "WREPL_STOP_ASSOCIATION");
682 proto_item_append_text(winsrepl_item, ", WREPL_STOP_ASSOCIATION");
683 dissect_winsrepl_stop(tvb, pinfo,
684 offset, winsrepl_tree);
685 break;
686 case WREPL_REPLICATION:
687 dissect_winsrepl_replication(tvb, pinfo,
688 offset, winsrepl_item, winsrepl_tree);
689 break;
692 return tvb_length(tvb);
695 static guint
696 get_winsrepl_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
698 guint pdu_len;
700 pdu_len=tvb_get_ntohl(tvb, offset);
701 return pdu_len+4;
704 static int
705 dissect_winsrepl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data)
707 tcp_dissect_pdus(tvb, pinfo, parent_tree, winsrepl_reassemble, 4, get_winsrepl_pdu_len, dissect_winsrepl_pdu, data);
708 return tvb_length(tvb);
711 void
712 proto_register_winsrepl(void)
714 static hf_register_info hf[] = {
715 { &hf_winsrepl_size, {
716 "Packet Size", "winsrepl.size",
717 FT_UINT32, BASE_DEC, NULL, 0x0,
718 "WINS Replication Packet Size", HFILL }},
720 { &hf_winsrepl_opcode, {
721 "Opcode", "winsrepl.opcode",
722 FT_UINT32, BASE_HEX, NULL, 0x0,
723 "WINS Replication Opcode", HFILL }},
725 { &hf_winsrepl_assoc_ctx, {
726 "Assoc_Ctx", "winsrepl.assoc_ctx",
727 FT_UINT32, BASE_HEX, NULL, 0x0,
728 "WINS Replication Assoc_Ctx", HFILL }},
730 { &hf_winsrepl_mess_type, {
731 "Message_Type", "winsrepl.message_type",
732 FT_UINT32, BASE_DEC, VALS(message_type_vals), 0x0,
733 "WINS Replication Message_Type", HFILL }},
735 { &hf_winsrepl_start_minor_version, {
736 "Minor Version", "winsrepl.minor_version",
737 FT_UINT16, BASE_DEC, NULL, 0x0,
738 "WINS Replication Minor Version", HFILL }},
740 { &hf_winsrepl_start_major_version, {
741 "Major Version", "winsrepl.major_version",
742 FT_UINT16, BASE_DEC, NULL, 0x0,
743 "WINS Replication Major Version", HFILL }},
745 { &hf_winsrepl_stop_reason, {
746 "Reason", "winsrepl.reason",
747 FT_UINT32, BASE_HEX, NULL, 0x0,
748 "WINS Replication Reason", HFILL }},
750 { &hf_winsrepl_replication_command, {
751 "Replication Command", "winsrepl.repl_cmd",
752 FT_UINT32, BASE_HEX, VALS(replication_cmd_vals), 0x0,
753 "WINS Replication Command", HFILL }},
755 { &hf_winsrepl_owner_address, {
756 "Owner Address", "winsrepl.owner_address",
757 FT_IPv4, BASE_NONE, NULL, 0x0,
758 "WINS Replication Owner Address", HFILL }},
760 { &hf_winsrepl_owner_max_version, {
761 "Max Version", "winsrepl.max_version",
762 FT_UINT64, BASE_DEC, NULL, 0x0,
763 "WINS Replication Max Version", HFILL }},
765 { &hf_winsrepl_owner_min_version, {
766 "Min Version", "winsrepl.min_version",
767 FT_UINT64, BASE_DEC, NULL, 0x0,
768 "WINS Replication Min Version", HFILL }},
770 { &hf_winsrepl_owner_type, {
771 "Owner Type", "winsrepl.owner_type",
772 FT_UINT32, BASE_DEC, NULL, 0x0,
773 "WINS Replication Owner Type", HFILL }},
775 { &hf_winsrepl_table_partner_count, {
776 "Partner Count", "winsrepl.partner_count",
777 FT_UINT32, BASE_DEC, NULL, 0x0,
778 "WINS Replication Partner Count", HFILL }},
780 { &hf_winsrepl_table_initiator, {
781 "Initiator", "winsrepl.initiator",
782 FT_IPv4, BASE_NONE, NULL, 0x0,
783 "WINS Replication Initiator", HFILL }},
785 { &hf_winsrepl_ip_owner, {
786 "IP Owner", "winsrepl.ip_owner",
787 FT_IPv4, BASE_NONE, NULL, 0x0,
788 "WINS Replication IP Owner", HFILL }},
790 { &hf_winsrepl_ip_ip, {
791 "IP Address", "winsrepl.ip_address",
792 FT_IPv4, BASE_NONE, NULL, 0x0,
793 "WINS Replication IP Address", HFILL }},
795 { &hf_winsrepl_addr_list_num_ips, {
796 "Num IPs", "winsrepl.num_ips",
797 FT_UINT32, BASE_DEC, NULL, 0x0,
798 "WINS Replication Num IPs", HFILL }},
800 { &hf_winsrepl_name_len, {
801 "Name Len", "winsrepl.name_len",
802 FT_UINT32, BASE_DEC, NULL, 0x0,
803 "WINS Replication Name Len", HFILL }},
805 { &hf_winsrepl_name_flags, {
806 "Name Flags", "winsrepl.name_flags",
807 FT_UINT32, BASE_HEX, NULL, 0x0,
808 "WINS Replication Name Flags", HFILL }},
810 { &hf_winsrepl_name_flags_rectype, {
811 "Record Type", "winsrepl.name_flags.rectype",
812 FT_UINT32, BASE_HEX, VALS(rectype_vals), 0x00000003,
813 "WINS Replication Name Flags Record Type", HFILL }},
815 { &hf_winsrepl_name_flags_recstate, {
816 "Record State", "winsrepl.name_flags.recstate",
817 FT_UINT32, BASE_HEX, VALS(recstate_vals), 0x0000000C,
818 "WINS Replication Name Flags Record State", HFILL }},
820 { &hf_winsrepl_name_flags_local, {
821 "Local", "winsrepl.name_flags.local",
822 FT_BOOLEAN, 32, NULL, 0x00000010,
823 "WINS Replication Name Flags Local Flag", HFILL }},
825 { &hf_winsrepl_name_flags_hosttype, {
826 "Host Type", "winsrepl.name_flags.hosttype",
827 FT_UINT32, BASE_HEX, VALS(hosttype_vals), 0x00000060,
828 "WINS Replication Name Flags Host Type", HFILL }},
830 { &hf_winsrepl_name_flags_static, {
831 "Static", "winsrepl.name_flags.static",
832 FT_BOOLEAN, 32, NULL, 0x00000080,
833 "WINS Replication Name Flags Static Flag", HFILL }},
835 { &hf_winsrepl_name_group_flag, {
836 "Name Group Flag", "winsrepl.name_group_flag",
837 FT_UINT32, BASE_HEX, NULL, 0x0,
838 "WINS Replication Name Group Flag", HFILL }},
840 { &hf_winsrepl_name_version_id, {
841 "Name Version Id", "winsrepl.name_version_id",
842 FT_UINT64, BASE_DEC, NULL, 0x0,
843 "WINS Replication Name Version Id", HFILL }},
845 { &hf_winsrepl_name_unknown, {
846 "Unknown IP", "winsrepl.unknown",
847 FT_IPv4, BASE_NONE, NULL, 0x0,
848 "WINS Replication Unknown IP", HFILL }},
850 { &hf_winsrepl_reply_num_names, {
851 "Num Names", "winsrepl.num_names",
852 FT_UINT32, BASE_DEC, NULL, 0x0,
853 "WINS Replication Num Names", HFILL }},
856 static gint *ett[] = {
857 &ett_winsrepl,
858 &ett_winsrepl_start,
859 &ett_winsrepl_stop,
860 &ett_winsrepl_replication,
861 &ett_winsrepl_owner,
862 &ett_winsrepl_table_reply,
863 &ett_winsrepl_ip,
864 &ett_winsrepl_addr_list,
865 &ett_winsrepl_name,
866 &ett_winsrepl_send_reply,
867 &ett_winsrepl_flags,
870 module_t *winsrepl_module;
872 proto_winsrepl = proto_register_protocol("WINS (Windows Internet Name Service) Replication",
873 "WINS-Replication", "winsrepl");
874 proto_register_subtree_array(ett, array_length(ett));
875 proto_register_field_array(proto_winsrepl, hf, array_length(hf));
877 winsrepl_module = prefs_register_protocol(proto_winsrepl, NULL);
878 prefs_register_bool_preference(winsrepl_module, "reassemble",
879 "Reassemble WINS-Replication messages spanning multiple TCP segments",
880 "Whether the WINS-Replication dissector should reassemble messages spanning multiple TCP segments."
881 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
882 &winsrepl_reassemble);
885 void
886 proto_reg_handoff_winsrepl(void)
888 dissector_handle_t winsrepl_handle;
890 winsrepl_handle = new_create_dissector_handle(dissect_winsrepl, proto_winsrepl);
891 dissector_add_uint("tcp.port", glb_winsrepl_tcp_port, winsrepl_handle);