23ba3d3dfc821e7194ed150ffbb5973326cf43cd
[obnox/wireshark/wip.git] / epan / dissectors / packet-winsrepl.c
1 /*
2  * packet-winsrepl.c
3  * 
4  * Routines for WINS Replication packet dissection
5  *
6  * Copyright 2005 Stefan Metzmacher <metze@samba.org>
7  *
8  * $Id$
9  *
10  * Ethereal - Network traffic analyzer
11  * By Gerald Combs <gerald@ethereal.com>
12  * Copyright 1998 Gerald Combs
13  *
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.
18  *
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.
23  *
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
27  */
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <stdio.h>
34
35 #include <time.h>
36 #include <string.h>
37 #include <glib.h>
38 #include <ctype.h>
39 #include <epan/packet.h>
40 #include <epan/conversation.h>
41 #include <epan/strutil.h>
42 #include <epan/prefs.h>
43 #include <epan/reassemble.h>
44 #include <epan/tap.h>
45
46 #include "packet-windows-common.h"
47 #include "packet-netbios.h"
48
49 #include "packet-winsrepl.h"
50
51 static gboolean winsrepl_reassemble = TRUE;
52
53 struct winsrepl_frame_data {
54         struct wrepl_wrap w;
55 };
56
57 static int proto_winsrepl = -1;
58
59 static int hf_winsrepl_size = -1;
60 static int hf_winsrepl_opcode = -1;
61 static int hf_winsrepl_assoc_ctx = -1;
62 static int hf_winsrepl_mess_type = -1;
63
64 static int hf_winsrepl_start_minor_version = -1;
65 static int hf_winsrepl_start_major_version = -1;
66
67 static int hf_winsrepl_stop_reason = -1;
68
69 static int hf_winsrepl_replication_command = -1;
70
71 static int hf_winsrepl_owner_address = -1;
72 static int hf_winsrepl_owner_max_version = -1;
73 static int hf_winsrepl_owner_min_version = -1;
74 static int hf_winsrepl_owner_type = -1;
75
76 static int hf_winsrepl_table_partner_count = -1;
77 static int hf_winsrepl_table_initiator = -1;
78
79 static int hf_winsrepl_ip_owner = -1;
80 static int hf_winsrepl_ip_ip = -1;
81 static int hf_winsrepl_addr_list_num_ips = -1;
82
83 static int hf_winsrepl_name_len = -1;
84 static int hf_winsrepl_name_flags = -1;
85 static int hf_winsrepl_name_group_flag = -1;
86 static int hf_winsrepl_name_id = -1;
87 static int hf_winsrepl_name_unknown = -1;
88
89 static int hf_winsrepl_reply_num_names = -1;
90
91 static gint ett_winsrepl = -1;
92
93 static gint ett_winsrepl_start = -1;
94 static gint ett_winsrepl_stop = -1;
95 static gint ett_winsrepl_replication = -1;
96
97 static gint ett_winsrepl_owner = -1;
98 static gint ett_winsrepl_table_reply = -1;
99
100 static gint ett_winsrepl_ip = -1;
101 static gint ett_winsrepl_addr_list = -1;
102
103 static gint ett_winsrepl_name = -1;
104 static gint ett_winsrepl_send_reply = -1;
105
106 dissector_handle_t winsrepl_handle;
107
108 static unsigned int glb_winsrepl_tcp_port = WINS_REPLICATION_PORT;
109
110 static const value_string replication_cmd_vals[] = {
111         {WREPL_REPL_TABLE_QUERY,        "WREPL_REPL_TABLE_QUERY"},
112         {WREPL_REPL_TABLE_REPLY,        "WREPL_REPL_TABLE_REPLY"},
113         {WREPL_REPL_SEND_REQUEST,       "WREPL_REPL_SEND_REQUEST"},
114         {WREPL_REPL_SEND_REPLY, "WREPL_REPL_SEND_REPLY"},
115         {WREPL_REPL_UPDATE,     "WREPL_REPL_UPDATE"},
116         {WREPL_REPL_INFORM,     "WREPL_REPL_INFORM"},
117         {0, NULL}
118 };
119
120 static const value_string message_type_vals[] = {
121         {WREPL_START_ASSOCIATION,       "WREPL_START_ASSOCIATION"},
122         {WREPL_START_ASSOCIATION_REPLY, "WREPL_START_ASSOCIATION_REPLY"},
123         {WREPL_STOP_ASSOCIATION,        "WREPL_STOP_ASSOCIATION"},
124         {WREPL_REPLICATION,     "WREPL_REPLICATION"},
125         {0, NULL}
126 };
127
128 static int
129 dissect_winsrepl_start(tvbuff_t *winsrepl_tvb, _U_ packet_info *pinfo,
130                        int winsrepl_offset, proto_tree *winsrepl_tree,
131                        struct winsrepl_frame_data *winsrepl)
132 {
133         struct wrepl_start *start = &winsrepl->w.packet.message.start;
134         proto_item *start_item = NULL;
135         proto_tree *start_tree = NULL;
136
137         if (winsrepl_tree) {
138                 start_item = proto_tree_add_text(winsrepl_tree, winsrepl_tvb, winsrepl_offset, -1 , "WREPL_START_ASSOCIATION");
139                 start_tree = proto_item_add_subtree(start_item, ett_winsrepl_start);
140         }
141
142         /* ASSOC_CTX */
143         start->assoc_ctx = tvb_get_ntohl(winsrepl_tvb, winsrepl_offset);
144         proto_tree_add_uint(start_tree, hf_winsrepl_assoc_ctx, winsrepl_tvb, winsrepl_offset, 4, start->assoc_ctx);
145         winsrepl_offset += 4;
146
147         /* MINOR VERSION */
148         start->minor_version = tvb_get_ntohs(winsrepl_tvb, winsrepl_offset);
149         proto_tree_add_uint(start_tree, hf_winsrepl_start_minor_version, winsrepl_tvb, winsrepl_offset, 2, start->minor_version);
150         winsrepl_offset += 2;
151
152         /* MAJOR VERSION */
153         start->major_version = tvb_get_ntohs(winsrepl_tvb, winsrepl_offset);
154         proto_tree_add_uint(start_tree, hf_winsrepl_start_major_version, winsrepl_tvb, winsrepl_offset, 2, start->major_version);
155         winsrepl_offset += 2;
156
157         return winsrepl_offset;
158 }
159
160 static int
161 dissect_winsrepl_stop(tvbuff_t *winsrepl_tvb, _U_ packet_info *pinfo,
162                       int winsrepl_offset, proto_tree *winsrepl_tree,
163                       struct winsrepl_frame_data *winsrepl)
164 {
165         struct wrepl_stop *stop = &winsrepl->w.packet.message.stop;
166         proto_item *stop_item = NULL;
167         proto_tree *stop_tree = NULL;
168
169         if (winsrepl_tree) {
170                 stop_item = proto_tree_add_text(winsrepl_tree, winsrepl_tvb, winsrepl_offset, -1 , "WREPL_STOP_ASSOCIATION");
171                 stop_tree = proto_item_add_subtree(stop_item, ett_winsrepl_stop);
172         }
173
174         /* REASON */
175         stop->reason = tvb_get_ntohl(winsrepl_tvb, winsrepl_offset);
176         proto_tree_add_uint(stop_tree, hf_winsrepl_stop_reason, winsrepl_tvb, winsrepl_offset, 4, stop->reason);
177         winsrepl_offset += 4;
178
179         return winsrepl_offset;
180 }
181
182 static int
183 dissect_winsrepl_table_query(tvbuff_t *winsrepl_tvb _U_, packet_info *pinfo _U_,
184                              int winsrepl_offset, proto_tree *winsrepl_tree _U_,
185                              struct winsrepl_frame_data *winsrepl _U_)
186 {
187         /* Nothing to do here */
188         return winsrepl_offset;
189 }
190
191 static int
192 dissect_winsrepl_wins_owner(tvbuff_t *winsrepl_tvb, _U_ packet_info *pinfo,
193                             int winsrepl_offset, proto_tree *winsrepl_tree,
194                             _U_ struct winsrepl_frame_data *winsrepl,
195                             struct wrepl_wins_owner *owner,
196                             proto_tree *sub_tree,
197                             guint32 index)
198 {
199         proto_item *owner_item = NULL;
200         proto_tree *owner_tree = NULL;
201         const guint8 *addr_ptr;
202         guint32 addr;
203
204         if (sub_tree) {
205                 owner_item = proto_tree_add_text(sub_tree, winsrepl_tvb, winsrepl_offset, 24 , "WINS Owner [%u]", index);
206                 owner_tree = proto_item_add_subtree(owner_item, ett_winsrepl_owner);
207         } else if (winsrepl_tree) {
208                 owner_item = proto_tree_add_text(winsrepl_tree, winsrepl_tvb, winsrepl_offset, 24 , "WINS Owner");
209                 owner_tree = proto_item_add_subtree(owner_item, ett_winsrepl_owner);
210         }
211
212         /* ADDRESS */
213         addr_ptr = tvb_get_ptr(winsrepl_tvb, winsrepl_offset, 4);
214         addr = tvb_get_letohl(winsrepl_tvb, winsrepl_offset);
215         SET_ADDRESS(&owner->address, AT_IPv4, 4, addr_ptr);
216         proto_tree_add_ipv4(owner_tree, hf_winsrepl_owner_address, winsrepl_tvb, winsrepl_offset, 4, addr);
217         winsrepl_offset += 4;
218
219         /* MAX_VERSION */
220         owner->max_version = tvb_get_ntoh64(winsrepl_tvb, winsrepl_offset);
221         proto_tree_add_uint64(owner_tree, hf_winsrepl_owner_max_version, winsrepl_tvb, winsrepl_offset, 8, owner->max_version);
222         winsrepl_offset += 8;
223
224         /* MIN_VERSION */
225         owner->min_version = tvb_get_ntoh64(winsrepl_tvb, winsrepl_offset);
226         proto_tree_add_uint64(owner_tree, hf_winsrepl_owner_min_version, winsrepl_tvb, winsrepl_offset, 8, owner->min_version);
227         winsrepl_offset += 8;
228
229         /* TYPE */
230         owner->type = tvb_get_ntohl(winsrepl_tvb, winsrepl_offset);
231         proto_tree_add_uint(owner_tree, hf_winsrepl_owner_type, winsrepl_tvb, winsrepl_offset, 4, owner->type);
232         winsrepl_offset += 4;
233
234         return winsrepl_offset;
235 }
236
237 static int
238 dissect_winsrepl_table_reply(tvbuff_t *winsrepl_tvb, packet_info *pinfo,
239                              int winsrepl_offset, proto_tree *winsrepl_tree,
240                              struct winsrepl_frame_data *winsrepl)
241 {
242         struct wrepl_table *table = &winsrepl->w.packet.message.replication.info.table;
243         struct wrepl_wins_owner owner;
244         proto_item *table_item = NULL;
245         proto_tree *table_tree = NULL;
246         const guint8 *initiator_ptr;
247         guint32 initiator;
248         guint32 i;
249
250         if (winsrepl_tree) {
251                 table_item = proto_tree_add_text(winsrepl_tree, winsrepl_tvb, winsrepl_offset, -1 , "WREPL_REPL_TABLE_REPLY");
252                 table_tree = proto_item_add_subtree(table_item, ett_winsrepl_table_reply);
253         }
254
255         /* PARTNER COUNT */
256         table->partner_count = tvb_get_ntohl(winsrepl_tvb, winsrepl_offset);
257         proto_tree_add_uint(table_tree, hf_winsrepl_table_partner_count, winsrepl_tvb, winsrepl_offset, 4, table->partner_count);
258         winsrepl_offset += 4;
259
260         for (i=0; i < table->partner_count; i++) {
261                 winsrepl_offset = dissect_winsrepl_wins_owner(winsrepl_tvb, pinfo,
262                                                               winsrepl_offset, table_tree,
263                                                               winsrepl, &owner, table_tree, i);
264         }
265
266         /* INITIATOR */
267         initiator_ptr= tvb_get_ptr(winsrepl_tvb, winsrepl_offset, 4);
268         initiator = tvb_get_letohl(winsrepl_tvb, winsrepl_offset);
269         SET_ADDRESS(&table->initiator, AT_IPv4, 4, initiator_ptr);
270         proto_tree_add_ipv4(table_tree, hf_winsrepl_table_initiator, winsrepl_tvb, winsrepl_offset, 4, initiator);
271         winsrepl_offset += 4;
272
273         return winsrepl_offset;
274 }
275
276 static int
277 dissect_winsrepl_send_request(tvbuff_t *winsrepl_tvb, packet_info *pinfo,
278                              int winsrepl_offset, proto_tree *winsrepl_tree,
279                              struct winsrepl_frame_data *winsrepl)
280 {
281         struct wrepl_wins_owner *owner = &winsrepl->w.packet.message.replication.info.owner;
282
283         winsrepl_offset = dissect_winsrepl_wins_owner(winsrepl_tvb, pinfo,
284                                                       winsrepl_offset, winsrepl_tree,
285                                                       winsrepl, owner, NULL, 0);
286
287         return winsrepl_offset;
288 }
289
290 static int
291 dissect_winsrepl_wins_ip(tvbuff_t *winsrepl_tvb, _U_ packet_info *pinfo,
292                          int winsrepl_offset, proto_tree *winsrepl_tree,
293                          _U_ struct winsrepl_frame_data *winsrepl,
294                          struct wrepl_ip *ip,
295                          proto_tree *sub_tree,
296                          guint32 index)
297 {
298         proto_item *ip_item = NULL;
299         proto_tree *ip_tree = NULL;
300         const guint8 *addr_ptr;
301         guint32 addr;
302
303         if (sub_tree) {
304                 ip_item = proto_tree_add_text(sub_tree, winsrepl_tvb, winsrepl_offset, 8 , "WINS IP [%u]", index);
305                 ip_tree = proto_item_add_subtree(ip_item, ett_winsrepl_ip);
306         } else if (winsrepl_tree) {
307                 ip_item = proto_tree_add_text(winsrepl_tree, winsrepl_tvb, winsrepl_offset, 8 , "WINS IP");
308                 ip_tree = proto_item_add_subtree(ip_item, ett_winsrepl_ip);
309         }
310
311         /* OWNER */
312         addr_ptr= tvb_get_ptr(winsrepl_tvb, winsrepl_offset, 4);
313         addr = tvb_get_letohl(winsrepl_tvb, winsrepl_offset);
314         SET_ADDRESS(&ip->owner, AT_IPv4, 4, addr_ptr);
315         proto_tree_add_ipv4(ip_tree, hf_winsrepl_ip_owner, winsrepl_tvb, winsrepl_offset, 4, addr);
316         winsrepl_offset += 4;
317
318         /* IP */
319         addr_ptr= tvb_get_ptr(winsrepl_tvb, winsrepl_offset, 4);
320         addr = tvb_get_letohl(winsrepl_tvb, winsrepl_offset);
321         SET_ADDRESS(&ip->ip, AT_IPv4, 4, addr_ptr);
322         proto_tree_add_ipv4(ip_tree, hf_winsrepl_ip_ip, winsrepl_tvb, winsrepl_offset, 4, addr);
323         proto_item_append_text(ip_item, ": %s", ip_to_str(ip->ip.data));
324         winsrepl_offset += 4;
325
326         return winsrepl_offset;
327 }
328
329 static int
330 dissect_winsrepl_wins_address_list(tvbuff_t *winsrepl_tvb, packet_info *pinfo,
331                                    int winsrepl_offset, proto_tree *winsrepl_tree,
332                                    struct winsrepl_frame_data *winsrepl,
333                                    struct wrepl_address_list *addresses,
334                                    proto_item *parent_item)
335 {
336         proto_item *addr_list_item = NULL;
337         proto_tree *addr_list_tree = NULL;
338         int old_offset = winsrepl_offset;
339         struct wrepl_ip ip;
340         guint32 i;
341
342         if (winsrepl_tree) {
343                 addr_list_item = proto_tree_add_text(winsrepl_tree, winsrepl_tvb, winsrepl_offset, -1 , "WINS Address LIst");
344                 addr_list_tree = proto_item_add_subtree(addr_list_item, ett_winsrepl_addr_list);
345         }
346
347         /* NUM_IPS */
348         addresses->num_ips = tvb_get_letohl(winsrepl_tvb, winsrepl_offset);
349         proto_tree_add_uint(addr_list_tree, hf_winsrepl_addr_list_num_ips, winsrepl_tvb, winsrepl_offset, 4, addresses->num_ips);
350         winsrepl_offset += 4;
351
352         for (i=0; i < addresses->num_ips; i++) {
353                 winsrepl_offset = dissect_winsrepl_wins_ip(winsrepl_tvb, pinfo,
354                                                            winsrepl_offset, addr_list_tree,
355                                                            winsrepl, &ip, addr_list_tree, i);
356                 if (i == 0) {
357                         proto_item_append_text(parent_item, ": %s", ip_to_str(ip.ip.data));
358                         proto_item_append_text(addr_list_item, ": %s", ip_to_str(ip.ip.data));
359                 } else {
360                         proto_item_append_text(parent_item, ", %s", ip_to_str(ip.ip.data));
361                         proto_item_append_text(addr_list_item, ", %s", ip_to_str(ip.ip.data));
362                 }
363         }
364
365         proto_item_set_len(addr_list_item, winsrepl_offset - old_offset);
366
367         return winsrepl_offset;
368 }
369
370 static int
371 dissect_winsrepl_wins_name(tvbuff_t *winsrepl_tvb, packet_info *pinfo,
372                            int winsrepl_offset, proto_tree *winsrepl_tree,
373                            struct winsrepl_frame_data *winsrepl,
374                            struct wrepl_wins_name *name,
375                            proto_tree *sub_tree,
376                            guint32 index)
377 {
378         proto_item *name_item = NULL;
379         proto_tree *name_tree = NULL;
380         int old_offset = winsrepl_offset;
381         tvbuff_t *name_tvb = NULL;
382         char  name_str[(NETBIOS_NAME_LEN - 1)*4 + 1];
383         int   name_type;
384         const guint8 *addr_ptr;
385         guint32 addr;
386
387         if (sub_tree) {
388                 name_item = proto_tree_add_text(sub_tree, winsrepl_tvb, winsrepl_offset, -1 , "WINS Name [%u]", index);
389                 name_tree = proto_item_add_subtree(name_item, ett_winsrepl_name);
390         } else if (winsrepl_tree) {
391                 name_item = proto_tree_add_text(winsrepl_tree, winsrepl_tvb, winsrepl_offset, -1 , "WINS Name");
392                 name_tree = proto_item_add_subtree(name_item, ett_winsrepl_name);
393         }
394
395         /* NAME_LEN */
396         name->name_len = tvb_get_ntohl(winsrepl_tvb, winsrepl_offset);
397         proto_tree_add_uint(name_tree, hf_winsrepl_name_len, winsrepl_tvb, winsrepl_offset, 4, name->name_len);
398         winsrepl_offset += 4;
399
400         /* NAME: TODO! */
401         name_tvb = tvb_new_subset(winsrepl_tvb, winsrepl_offset, name->name_len, name->name_len);
402         netbios_add_name("Name", name_tvb, 0, name_tree);
403         name_type = get_netbios_name(name_tvb, 0, name_str);
404         proto_item_append_text(name_item, ": %s<%02x>", name_str, name_type);
405         winsrepl_offset += name->name_len;
406
407         /* ALIGN to 4 Byte */
408         winsrepl_offset += ((winsrepl_offset & (4-1)) == 0 ? 0 : (4 - (winsrepl_offset & (4-1))));
409
410         /* FLAGS */
411         name->flags = tvb_get_ntohl(winsrepl_tvb, winsrepl_offset);
412         proto_tree_add_uint(name_tree, hf_winsrepl_name_flags, winsrepl_tvb, winsrepl_offset, 4, name->flags);
413         winsrepl_offset += 4;
414
415         /* GROUP_FLAG */
416         name->group_flag = tvb_get_letohl(winsrepl_tvb, winsrepl_offset);
417         proto_tree_add_uint(name_tree, hf_winsrepl_name_group_flag, winsrepl_tvb, winsrepl_offset, 4, name->group_flag);
418         winsrepl_offset += 4;
419
420         /* ID */
421         name->id = tvb_get_ntoh64(winsrepl_tvb, winsrepl_offset);
422         proto_tree_add_uint64(name_tree, hf_winsrepl_name_id, winsrepl_tvb, winsrepl_offset, 8, name->id);
423         winsrepl_offset += 8;
424
425         switch (name->flags & 2) {
426                 case 0:
427                         /* IP */
428                         addr_ptr= tvb_get_ptr(winsrepl_tvb, winsrepl_offset, 4);
429                         addr = tvb_get_letohl(winsrepl_tvb, winsrepl_offset);
430                         SET_ADDRESS(&name->addresses.ip, AT_IPv4, 4, addr_ptr);
431                         proto_tree_add_ipv4(name_tree, hf_winsrepl_ip_ip, winsrepl_tvb, winsrepl_offset, 4, addr);
432                         proto_item_append_text(name_item, ": %s", ip_to_str(name->addresses.ip.data));
433                         winsrepl_offset += 4;
434                         break;
435                 case 2:
436                         winsrepl_offset = dissect_winsrepl_wins_address_list(winsrepl_tvb, pinfo,
437                                                                              winsrepl_offset, name_tree,
438                                                                              winsrepl, &name->addresses.addresses, name_item);
439                         break;
440         }
441
442
443         /* UNKNOWN, little or big endian??? */
444         addr_ptr= tvb_get_ptr(winsrepl_tvb, winsrepl_offset, 4);
445         addr = tvb_get_letohl(winsrepl_tvb, winsrepl_offset);
446         SET_ADDRESS(&name->unknown, AT_IPv4, 4, addr_ptr);
447         proto_tree_add_ipv4(name_tree, hf_winsrepl_name_unknown, winsrepl_tvb, winsrepl_offset, 4, addr);
448         winsrepl_offset += 4;
449
450         proto_item_set_len(name_item, winsrepl_offset - old_offset);
451
452         return winsrepl_offset;
453 }
454
455 static int
456 dissect_winsrepl_send_reply(tvbuff_t *winsrepl_tvb, packet_info *pinfo,
457                             int winsrepl_offset, proto_tree *winsrepl_tree,
458                             struct winsrepl_frame_data *winsrepl)
459 {
460         struct wrepl_send_reply *reply = &winsrepl->w.packet.message.replication.info.reply;
461         struct wrepl_wins_name name;
462         proto_item *rep_item = NULL;
463         proto_tree *rep_tree = NULL;
464         guint32 i;
465
466         if (winsrepl_tree) {
467                 rep_item = proto_tree_add_text(winsrepl_tree, winsrepl_tvb, winsrepl_offset, -1 , "WREPL_REPL_SEND_REPLY");
468                 rep_tree = proto_item_add_subtree(rep_item, ett_winsrepl_send_reply);
469         }
470
471         /* NUM NAMES */
472         reply->num_names = tvb_get_ntohl(winsrepl_tvb, winsrepl_offset);
473         proto_tree_add_uint(rep_tree, hf_winsrepl_reply_num_names, winsrepl_tvb, winsrepl_offset, 4, reply->num_names);
474         winsrepl_offset += 4;
475
476         for (i=0; i < reply->num_names; i++) {
477                 winsrepl_offset = dissect_winsrepl_wins_name(winsrepl_tvb, pinfo,
478                                                              winsrepl_offset, rep_tree,
479                                                              winsrepl, &name, rep_tree, i);
480         }
481
482         return winsrepl_offset;
483 }
484
485 static int
486 dissect_winsrepl_update(tvbuff_t *winsrepl_tvb _U_, packet_info *pinfo _U_,
487                         int winsrepl_offset, proto_tree *winsrepl_tree _U_,
488                         struct winsrepl_frame_data *winsrepl _U_)
489 {
490         return winsrepl_offset;
491 }
492
493 static int
494 dissect_winsrepl_inform(tvbuff_t *winsrepl_tvb, packet_info *pinfo,
495                         int winsrepl_offset, proto_tree *winsrepl_tree,
496                         struct winsrepl_frame_data *winsrepl)
497 {
498         winsrepl_offset = dissect_winsrepl_table_reply(winsrepl_tvb, pinfo,
499                                                        winsrepl_offset, winsrepl_tree,
500                                                        winsrepl);
501         return winsrepl_offset;
502 }
503
504 static int
505 dissect_winsrepl_5_or_9(tvbuff_t *winsrepl_tvb, packet_info *pinfo,
506                         int winsrepl_offset, proto_tree *winsrepl_tree,
507                         struct winsrepl_frame_data *winsrepl)
508 {
509         winsrepl_offset = dissect_winsrepl_table_reply(winsrepl_tvb, pinfo,
510                                                        winsrepl_offset, winsrepl_tree,
511                                                        winsrepl);
512         return winsrepl_offset;
513 }
514
515 static int
516 dissect_winsrepl_replication(tvbuff_t *winsrepl_tvb, packet_info *pinfo,
517                              int winsrepl_offset, proto_tree *winsrepl_tree,
518                              struct winsrepl_frame_data *winsrepl)
519 {
520         struct wrepl_replication *repl = &winsrepl->w.packet.message.replication;
521         proto_item *repl_item = NULL;
522         proto_tree *repl_tree = NULL;
523
524         if (winsrepl_tree) {
525                 repl_item = proto_tree_add_text(winsrepl_tree, winsrepl_tvb, winsrepl_offset, -1 , "WREPL_REPLICATION");
526                 repl_tree = proto_item_add_subtree(repl_item, ett_winsrepl_replication);
527         }
528         
529         /* REPLIICATION_CMD */
530         repl->command = tvb_get_ntohl(winsrepl_tvb, winsrepl_offset);
531         proto_tree_add_uint(repl_tree, hf_winsrepl_replication_command, winsrepl_tvb, winsrepl_offset, 4, repl->command);
532         winsrepl_offset += 4;
533
534         switch (repl->command) {
535                 case WREPL_REPL_TABLE_QUERY:
536                         winsrepl_offset = dissect_winsrepl_table_query(winsrepl_tvb, pinfo,
537                                                                        winsrepl_offset, repl_tree,
538                                                                        winsrepl);
539                         break;
540                 case WREPL_REPL_TABLE_REPLY:
541                         winsrepl_offset = dissect_winsrepl_table_reply(winsrepl_tvb, pinfo,
542                                                                        winsrepl_offset, repl_tree,
543                                                                        winsrepl);
544                         break;
545                 case WREPL_REPL_SEND_REQUEST:
546                         winsrepl_offset = dissect_winsrepl_send_request(winsrepl_tvb, pinfo,
547                                                                         winsrepl_offset, repl_tree,
548                                                                         winsrepl);
549                         break;
550                 case WREPL_REPL_SEND_REPLY:
551                         winsrepl_offset = dissect_winsrepl_send_reply(winsrepl_tvb, pinfo,
552                                                                       winsrepl_offset, repl_tree,
553                                                                       winsrepl);
554                         break;
555                 case WREPL_REPL_UPDATE:
556                         winsrepl_offset = dissect_winsrepl_update(winsrepl_tvb, pinfo,
557                                                                   winsrepl_offset, repl_tree,
558                                                                   winsrepl);
559                         break;
560                 case WREPL_REPL_5:
561                 case WREPL_REPL_9:
562                         winsrepl_offset = dissect_winsrepl_5_or_9(winsrepl_tvb, pinfo,
563                                                                   winsrepl_offset, repl_tree,
564                                                                   winsrepl);
565                         break;
566                 case WREPL_REPL_INFORM:
567                         winsrepl_offset = dissect_winsrepl_inform(winsrepl_tvb, pinfo,
568                                                                   winsrepl_offset, repl_tree,
569                                                                   winsrepl);
570                         break;
571         }
572
573         return winsrepl_offset;
574 }
575
576 static void
577 dissect_winsrepl_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
578 {
579         int winsrepl_offset = 0;
580         tvbuff_t *winsrepl_tvb = NULL;
581         proto_item *winsrepl_item = NULL;
582         proto_tree *winsrepl_tree = NULL;
583         struct winsrepl_frame_data _winsrepl_frame;
584         struct winsrepl_frame_data *winsrepl = &_winsrepl_frame;
585
586         if (check_col(pinfo->cinfo, COL_PROTOCOL)){
587                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "WINS-Replication");
588         }
589         if (check_col(pinfo->cinfo, COL_INFO)){
590                 col_clear(pinfo->cinfo, COL_INFO);
591         }
592
593         winsrepl_tvb = tvb_new_subset(tvb, 0, -1, -1);
594
595         if (parent_tree) {
596                 winsrepl_item = proto_tree_add_item(parent_tree, proto_winsrepl, winsrepl_tvb, winsrepl_offset, -1, FALSE);
597                 winsrepl_tree = proto_item_add_subtree(winsrepl_item, ett_winsrepl);
598         }
599
600         /* SIZE */
601         winsrepl->w.size = tvb_get_ntohl(winsrepl_tvb, winsrepl_offset);
602         proto_tree_add_uint(winsrepl_tree, hf_winsrepl_size, winsrepl_tvb, winsrepl_offset, 4, winsrepl->w.size);
603         winsrepl_offset += 4;
604
605         proto_item_set_len(winsrepl_item, winsrepl->w.size + 4);
606
607         /* OPCODE */
608         winsrepl->w.packet.opcode = tvb_get_ntohl(winsrepl_tvb, winsrepl_offset);
609         proto_tree_add_uint(winsrepl_tree, hf_winsrepl_opcode, winsrepl_tvb, winsrepl_offset, 4, winsrepl->w.packet.opcode);
610         winsrepl_offset += 4;
611
612         /* ASSOC_CTX */
613         winsrepl->w.packet.assoc_ctx = tvb_get_ntohl(winsrepl_tvb, winsrepl_offset);
614         proto_tree_add_uint(winsrepl_tree, hf_winsrepl_assoc_ctx, winsrepl_tvb, winsrepl_offset, 4, winsrepl->w.packet.assoc_ctx);
615         winsrepl_offset += 4;
616
617         /* MESSAGE_TYPE */
618         winsrepl->w.packet.mess_type = tvb_get_ntohl(winsrepl_tvb, winsrepl_offset);
619         proto_tree_add_uint(winsrepl_tree, hf_winsrepl_mess_type, winsrepl_tvb, winsrepl_offset, 4, winsrepl->w.packet.mess_type);
620         winsrepl_offset += 4;
621
622         switch (winsrepl->w.packet.mess_type) {
623                 case WREPL_START_ASSOCIATION:
624                         winsrepl_offset = dissect_winsrepl_start(winsrepl_tvb, pinfo,
625                                                                  winsrepl_offset, winsrepl_tree,
626                                                                  winsrepl);
627                         break;
628                 case WREPL_START_ASSOCIATION_REPLY:
629                         winsrepl_offset = dissect_winsrepl_start(winsrepl_tvb, pinfo,
630                                                                  winsrepl_offset, winsrepl_tree,
631                                                                  winsrepl);
632                         break;
633                 case WREPL_STOP_ASSOCIATION:
634                         winsrepl_offset = dissect_winsrepl_stop(winsrepl_tvb, pinfo,
635                                                                 winsrepl_offset, winsrepl_tree,
636                                                                 winsrepl);
637                         break;
638                 case WREPL_REPLICATION:
639                         winsrepl_offset = dissect_winsrepl_replication(winsrepl_tvb, pinfo,
640                                                                        winsrepl_offset, winsrepl_tree,
641                                                                        winsrepl);
642                         break;
643         }
644
645         return;
646 }
647
648 static void
649 dissect_winsrepl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
650 {
651         int offset = 0;
652
653         if (!winsrepl_reassemble || !pinfo->can_desegment) {
654                 dissect_winsrepl_pdu(tvb, pinfo, parent_tree);
655                 return;
656         }
657
658         while (tvb_reported_length_remaining(tvb, offset) > 0) {
659                 guint length_remaining = 0;
660                 tvbuff_t *pdu_tvb = NULL;
661                 guint32 pdu_size = 0;
662
663                 length_remaining = tvb_ensure_length_remaining(tvb, offset);
664                 if (length_remaining < 4) {
665                         pinfo->desegment_offset = offset;
666                         pinfo->desegment_len    = 4 - length_remaining;
667                         return;
668                 }
669
670                 pdu_size = tvb_get_ntohl(tvb, offset);
671                 pdu_size += 4;
672
673                 if (length_remaining < pdu_size) {
674                         pinfo->want_pdu_tracking        = 2;
675                         pinfo->bytes_until_next_pdu     = pdu_size - length_remaining;
676                         pinfo->desegment_offset = offset;
677                         pinfo->desegment_len    = pdu_size - length_remaining;
678                         return;
679                 }
680
681                 pdu_tvb = tvb_new_subset(tvb, offset, pdu_size, pdu_size);
682
683                 dissect_winsrepl_pdu(pdu_tvb, pinfo, parent_tree);
684
685                 offset += pdu_size;
686         }
687
688         return;
689 }
690
691 void
692 proto_register_winsrepl(void)
693 {
694         static hf_register_info hf[] = {
695                 { &hf_winsrepl_size, {
696                         "Packet Size", "winsrepl.size",
697                         FT_UINT32, BASE_DEC, NULL, 0x0,
698                         "WINS Replication Packet Size", HFILL }},
699
700                 { &hf_winsrepl_opcode, {
701                         "Opcode", "winsrepl.opcode",
702                         FT_UINT32, BASE_HEX, NULL, 0x0,
703                         "WINS Replication Opcode", HFILL }},
704
705                 { &hf_winsrepl_assoc_ctx, {
706                         "Assoc_Ctx", "winsrepl.assoc_ctx",
707                         FT_UINT32, BASE_HEX, NULL, 0x0,
708                         "WINS Replication Assoc_Ctx", HFILL }},
709
710                 { &hf_winsrepl_mess_type, {
711                         "Assoc_Ctx", "winsrepl.message_type",
712                         FT_UINT32, BASE_DEC, VALS(message_type_vals), 0x0,
713                         "WINS Replication Message_Type", HFILL }},
714
715                 { &hf_winsrepl_start_minor_version, {
716                         "Minor Version", "winsrepl.minor_version",
717                         FT_UINT16, BASE_DEC, NULL, 0x0,
718                         "WINS Replication Minor Version", HFILL }},
719
720                 { &hf_winsrepl_start_major_version, {
721                         "Major Version", "winsrepl.major_version",
722                         FT_UINT16, BASE_DEC, NULL, 0x0,
723                         "WINS Replication Major Version", HFILL }},
724
725                 { &hf_winsrepl_stop_reason, {
726                         "Reason", "winsrepl.reason",
727                         FT_UINT32, BASE_HEX, NULL, 0x0,
728                         "WINS Replication Reason", HFILL }},
729
730                 { &hf_winsrepl_replication_command, {
731                         "Replication Command", "winsrepl.repl_cmd",
732                         FT_UINT32, BASE_HEX, VALS(replication_cmd_vals), 0x0,
733                         "WINS Replication Command", HFILL }},
734
735                 { &hf_winsrepl_owner_address, {
736                         "Owner Address", "winsrepl.owner_address",
737                         FT_IPv4, BASE_NONE, NULL, 0x0,
738                         "WINS Replication Owner Address", HFILL }},
739
740                 { &hf_winsrepl_owner_max_version, {
741                         "Max Version", "winsrepl.max_version",
742                         FT_UINT64, BASE_DEC, NULL, 0x0,
743                         "WINS Replication Max Version", HFILL }},
744
745                 { &hf_winsrepl_owner_min_version, {
746                         "Min Version", "winsrepl.min_version",
747                         FT_UINT64, BASE_DEC, NULL, 0x0,
748                         "WINS Replication Min Version", HFILL }},
749
750                 { &hf_winsrepl_owner_type, {
751                         "Owner Type", "winsrepl.owner_type",
752                         FT_UINT32, BASE_DEC, NULL, 0x0,
753                         "WINS Replication Owner Type", HFILL }},
754
755                 { &hf_winsrepl_table_partner_count, {
756                         "Partner Count", "winsrepl.partner_count",
757                         FT_UINT32, BASE_DEC, NULL, 0x0,
758                         "WINS Replication Partner Count", HFILL }},
759
760                 { &hf_winsrepl_table_initiator, {
761                         "Initiator", "winsrepl.initiator",
762                         FT_IPv4, BASE_NONE, NULL, 0x0,
763                         "WINS Replication Initiator", HFILL }},
764
765                 { &hf_winsrepl_ip_owner, {
766                         "IP Owner", "winsrepl.ip_owner",
767                         FT_IPv4, BASE_NONE, NULL, 0x0,
768                         "WINS Replication IP Owner", HFILL }},
769
770                 { &hf_winsrepl_ip_ip, {
771                         "IP Address", "winsrepl.ip_address",
772                         FT_IPv4, BASE_NONE, NULL, 0x0,
773                         "WINS Replication IP Address", HFILL }},
774
775                 { &hf_winsrepl_addr_list_num_ips, {
776                         "Num IPs", "winsrepl.num_ips",
777                         FT_UINT32, BASE_DEC, NULL, 0x0,
778                         "WINS Replication Num IPs", HFILL }},
779
780                 { &hf_winsrepl_name_len, {
781                         "Name Len", "winsrepl.name_len",
782                         FT_UINT32, BASE_DEC, NULL, 0x0,
783                         "WINS Replication Name Len", HFILL }},
784
785                 { &hf_winsrepl_name_flags, {
786                         "Name Flags", "winsrepl.name_flags",
787                         FT_UINT32, BASE_HEX, NULL, 0x0,
788                         "WINS Replication Name Flags", HFILL }},
789
790                 { &hf_winsrepl_name_group_flag, {
791                         "Name Group Flag", "winsrepl.name_group_flag",
792                         FT_UINT32, BASE_HEX, NULL, 0x0,
793                         "WINS Replication Name Group Flag", HFILL }},
794
795                 { &hf_winsrepl_name_id, {
796                         "Name Id", "winsrepl.name_id",
797                         FT_UINT64, BASE_DEC, NULL, 0x0,
798                         "WINS Replication Name Id", HFILL }},
799
800                 { &hf_winsrepl_name_unknown, {
801                         "Unknown IP", "winsrepl.unknown",
802                         FT_IPv4, BASE_NONE, NULL, 0x0,
803                         "WINS Replication Unknown IP", HFILL }},
804
805                 { &hf_winsrepl_reply_num_names, {
806                         "Num Names", "winsrepl.num_names",
807                         FT_UINT32, BASE_DEC, NULL, 0x0,
808                         "WINS Replication Num Names", HFILL }},
809         };
810
811         static gint *ett[] = {
812                 &ett_winsrepl,
813                 &ett_winsrepl_start,
814                 &ett_winsrepl_stop,
815                 &ett_winsrepl_replication,
816                 &ett_winsrepl_owner,
817                 &ett_winsrepl_table_reply,
818                 &ett_winsrepl_ip,
819                 &ett_winsrepl_addr_list,
820                 &ett_winsrepl_name,
821                 &ett_winsrepl_send_reply,
822         };
823
824         module_t *winsrepl_module;
825
826         proto_winsrepl = proto_register_protocol("WINS (Windows Internet Name Service) Replication",
827                                                  "WINS-Replication", "winsrepl");
828         proto_register_subtree_array(ett, array_length(ett));
829         proto_register_field_array(proto_winsrepl, hf, array_length(hf));
830
831         winsrepl_module = prefs_register_protocol(proto_winsrepl, NULL);
832         prefs_register_bool_preference(winsrepl_module, "reassemble",
833                 "Reassemble WINS-Replication messages spanning multiple TCP segments",
834                 "Whether the WINS-Replication dissector should reassemble messages spanning multiple TCP segments."
835                 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
836                 &winsrepl_reassemble);
837 }
838
839 void
840 proto_reg_handoff_winsrepl(void)
841 {
842         winsrepl_handle = create_dissector_handle(dissect_winsrepl, proto_winsrepl);
843         dissector_add("tcp.port", glb_winsrepl_tcp_port, winsrepl_handle);
844 }