* Modified Makefile.am and configure.in so that wiretap isn't built unless
[obnox/wireshark/wip.git] / packet-nbns.c
1 /* packet-nbns.c
2  * Routines for NetBIOS Name Service packet disassembly
3  * Gilbert Ramirez <gram@verdict.uthscsa.edu>
4  * Much stuff added by Guy Harris <guy@netapp.com>
5  *
6  * $Id: packet-nbns.c,v 1.13 1999/01/05 09:01:42 guy Exp $
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@zing.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * 
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  * 
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  * 
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <gtk/gtk.h>
33
34 #include <stdio.h>
35 #include <string.h>
36 #include <memory.h>
37
38 #ifdef HAVE_SYS_TYPES_H
39 # include <sys/types.h>
40 #endif
41
42 #ifdef HAVE_NETINET_IN_H
43 # include <netinet/in.h>
44 #endif
45
46 #include "ethereal.h"
47 #include "packet.h"
48 #include "packet-dns.h"
49 #include "util.h"
50
51 /* Packet structure taken from RFC 1002. See also RFC 1001.
52  * Opcode, flags, and rcode treated as "flags", similarly to DNS,
53  * to make it easier to lift the dissection code from "packet-dns.c". */
54
55 /* Offsets of fields in the NBNS header. */
56 #define NBNS_ID         0
57 #define NBNS_FLAGS      2
58 #define NBNS_QUEST      4
59 #define NBNS_ANS        6
60 #define NBNS_AUTH       8
61 #define NBNS_ADD        10
62
63 /* Length of NBNS header. */
64 #define NBNS_HDRLEN     12
65
66 /* type values  */
67 #define T_NB            32              /* NetBIOS name service RR */
68 #define T_NBSTAT        33              /* NetBIOS node status RR */
69
70 /* NetBIOS datagram packet, from RFC 1002, page 32 */
71 struct nbdgm_header {
72         guint8          msg_type;
73         struct {
74                 guint8  more;
75                 guint8  first;
76                 guint8  node_type;
77         } flags;
78         guint16         dgm_id;
79         guint32         src_ip;
80         guint16         src_port;
81
82         /* For packets with data */
83         guint16         dgm_length;
84         guint16         pkt_offset;
85
86         /* For error packets */
87         guint8          error_code;
88 };
89
90 /* Bit fields in the flags */
91 #define F_RESPONSE      (1<<15)         /* packet is response */
92 #define F_OPCODE        (0xF<<11)       /* query opcode */
93 #define F_AUTHORITATIVE (1<<10)         /* response is authoritative */
94 #define F_TRUNCATED     (1<<9)          /* response is truncated */
95 #define F_RECDESIRED    (1<<8)          /* recursion desired */
96 #define F_RECAVAIL      (1<<7)          /* recursion available */
97 #define F_BROADCAST     (1<<4)          /* broadcast/multicast packet */
98 #define F_RCODE         (0xF<<0)        /* reply code */
99
100 /* Opcodes */
101 #define OPCODE_QUERY          (0<<11)    /* standard query */
102 #define OPCODE_REGISTRATION   (5<<11)    /* registration */
103 #define OPCODE_RELEASE        (6<<11)    /* release name */
104 #define OPCODE_WACK           (7<<11)    /* wait for acknowledgement */
105 #define OPCODE_REFRESH        (8<<11)    /* refresh registration */
106 #define OPCODE_REFRESHALT     (9<<11)    /* refresh registration (alternate opcode) */
107 #define OPCODE_MHREGISTRATION (15<<11)   /* multi-homed registration */
108
109 /* Reply codes */
110 #define RCODE_NOERROR   (0<<0)
111 #define RCODE_FMTERROR  (1<<0)
112 #define RCODE_SERVFAIL  (2<<0)
113 #define RCODE_NAMEERROR (3<<0)
114 #define RCODE_NOTIMPL   (4<<0)
115 #define RCODE_REFUSED   (5<<0)
116 #define RCODE_ACTIVE    (6<<0)
117 #define RCODE_CONFLICT  (7<<0)
118
119 /* Values for the "NB_FLAGS" field of RR data.  From RFC 1001 and 1002,
120  * except for NB_FLAGS_ONT_H_NODE, which was discovered by looking at
121  * packet traces. */
122 #define NB_FLAGS_ONT            (3<<(15-2))     /* bits for node type */
123 #define NB_FLAGS_ONT_B_NODE     (0<<(15-2))     /* B-mode node */
124 #define NB_FLAGS_ONT_P_NODE     (1<<(15-2))     /* P-mode node */
125 #define NB_FLAGS_ONT_M_NODE     (2<<(15-2))     /* M-mode node */
126 #define NB_FLAGS_ONT_H_NODE     (3<<(15-2))     /* H-mode node */
127
128 #define NB_FLAGS_G              (1<<(15-0))     /* group name */
129
130 /* Values for the "NAME_FLAGS" field of a NODE_NAME entry in T_NBSTAT
131  * RR data.  From RFC 1001 and 1002, except for NAME_FLAGS_ONT_H_NODE,
132  * which was discovered by looking at packet traces. */
133 #define NAME_FLAGS_PRM          (1<<(15-6))     /* name is permanent node name */
134
135 #define NAME_FLAGS_ACT          (1<<(15-5))     /* name is active */
136
137 #define NAME_FLAGS_CNF          (1<<(15-4))     /* name is in conflict */
138
139 #define NAME_FLAGS_DRG          (1<<(15-3))     /* name is being deregistered */
140
141 #define NAME_FLAGS_ONT          (3<<(15-2))     /* bits for node type */
142 #define NAME_FLAGS_ONT_B_NODE   (0<<(15-2))     /* B-mode node */
143 #define NAME_FLAGS_ONT_P_NODE   (1<<(15-2))     /* P-mode node */
144 #define NAME_FLAGS_ONT_M_NODE   (2<<(15-2))     /* M-mode node */
145
146 #define NAME_FLAGS_G            (1<<(15-0))     /* group name */
147
148 static const value_string opcode_vals[] = {
149           { OPCODE_QUERY,          "Name query"                 },
150           { OPCODE_REGISTRATION,   "Registration"               },
151           { OPCODE_RELEASE,        "Release"                    },
152           { OPCODE_WACK,           "Wait for acknowledgment"    },
153           { OPCODE_REFRESH,        "Refresh"                    },
154           { OPCODE_REFRESHALT,     "Refresh (alternate opcode)" },
155           { OPCODE_MHREGISTRATION, "Multi-homed registration"   },
156           { 0,                     NULL                         }
157 };
158
159 static char *
160 nbns_type_name (int type)
161 {
162         switch (type) {
163         case T_NB:
164                 return "NB";
165         case T_NBSTAT:
166                 return "NBSTAT";
167         }
168         
169         return "unknown";
170 }
171
172 /* "Canonicalize" a 16-character NetBIOS name by:
173  *
174  *      removing and saving the last byte;
175  *
176  *      stripping trailing blanks;
177  *
178  *      appending the trailing byte, as a hex number, in square brackets. */
179 static char *
180 canonicalize_netbios_name(char *nbname)
181 {
182         char *pnbname;
183         u_char lastchar;
184
185         /* Get the last character of the name, as it's a special number
186          * indicating the type of the name, rather than part of the name
187          * *per se*. */
188         pnbname = nbname + 15;  /* point to the 16th character */
189         lastchar = *(unsigned char *)pnbname;
190
191         /* Now strip off any trailing blanks used to pad it to
192          * 16 bytes. */
193         while (pnbname > &nbname[0]) {
194                 if (*(pnbname - 1) != ' ')
195                         break;          /* found non-blank character */
196                 pnbname--;              /* blank - skip over it */
197         }
198
199         /* Replace the last character with its hex value, in square
200          * brackets, to make it easier to tell what it is. */
201         sprintf(pnbname, "[%02X]", lastchar);
202         pnbname += 4;
203         return pnbname;
204 }
205
206 static int
207 get_nbns_name(const u_char *nbns_data_ptr, const u_char *pd,
208     int offset, char *name_ret)
209 {
210         int name_len;
211         char name[MAXDNAME];
212         char nbname[MAXDNAME+4];        /* 4 for [<last char>] */
213         char *pname, *pnbname, cname, cnbname;
214
215         name_len = get_dns_name(nbns_data_ptr, pd, offset, name, sizeof(name));
216         
217         /* OK, now undo the first-level encoding. */
218         pname = &name[0];
219         pnbname = &nbname[0];
220         for (;;) {
221                 /* Every two characters of the first level-encoded name
222                  * turn into one character in the decoded name. */
223                 cname = *pname;
224                 if (cname == '\0')
225                         break;          /* no more characters */
226                 if (cname == '.')
227                         break;          /* scope ID follows */
228                 if (cname < 'A' || cname > 'Z') {
229                         /* Not legal. */
230                         strcpy(nbname,
231                             "Illegal NetBIOS name (character not between A and Z in first-level encoding)");
232                         goto bad;
233                 }
234                 cname -= 'A';
235                 cnbname = cname << 4;
236                 pname++;
237
238                 cname = *pname;
239                 if (cname == '\0' || cname == '.') {
240                         /* No more characters in the name - but we're in
241                          * the middle of a pair.  Not legal. */
242                         strcpy(nbname,
243                             "Illegal NetBIOS name (odd number of bytes)");
244                         goto bad;
245                 }
246                 if (cname < 'A' || cname > 'Z') {
247                         /* Not legal. */
248                         strcpy(nbname,
249                             "Illegal NetBIOS name (character not between A and Z in first-level encoding)");
250                         goto bad;
251                 }
252                 cname -= 'A';
253                 cnbname |= cname;
254                 pname++;
255
256                 /* Store the character. */
257                 *pnbname++ = cnbname;
258         }
259
260         /* NetBIOS names are supposed to be exactly 16 bytes long. */
261         if (pnbname - nbname == 16) {
262                 /* This one is; canonicalize its name. */
263                 pnbname = canonicalize_netbios_name(nbname);
264         } else {
265                 sprintf(nbname, "Illegal NetBIOS name (%ld bytes long)",
266                     (long)(pnbname - nbname));
267                 goto bad;
268         }
269         if (cname == '.') {
270                 /* We have a scope ID, starting at "pname"; append that to
271                  * the decoded host name. */
272                 strcpy(pnbname, pname);
273         } else {
274                 /* Terminate the decoded host name. */
275                 *pnbname = '\0';
276         }
277
278 bad:
279         strcpy (name_ret, nbname);
280         return name_len;
281 }
282
283
284 static int
285 get_nbns_name_type_class(const u_char *nbns_data_ptr, const u_char *pd,
286     int offset, char *name_ret, int *name_len_ret, int *type_ret,
287     int *class_ret)
288 {
289         int name_len;
290         int type;
291         int class;
292
293         name_len = get_nbns_name(nbns_data_ptr, pd, offset, name_ret);
294         offset += name_len;
295         
296         type = pntohs(&pd[offset]);
297         offset += 2;
298         class = pntohs(&pd[offset]);
299
300         *type_ret = type;
301         *class_ret = class;
302         *name_len_ret = name_len;
303
304         return name_len + 4;
305 }
306
307
308 static int
309 dissect_nbns_query(const u_char *nbns_data_ptr, const u_char *pd, int offset,
310     GtkWidget *nbns_tree)
311 {
312         int len;
313         char name[MAXDNAME];
314         int name_len;
315         int type;
316         int class;
317         char *class_name;
318         char *type_name;
319         const u_char *dptr;
320         const u_char *data_start;
321         GtkWidget *q_tree, *tq;
322
323         data_start = dptr = pd + offset;
324
325         len = get_nbns_name_type_class(nbns_data_ptr, pd, offset, name,
326             &name_len, &type, &class);
327         dptr += len;
328
329         type_name = nbns_type_name(type);
330         class_name = dns_class_name(class);
331
332         tq = add_item_to_tree(nbns_tree, offset, len, "%s: type %s, class %s", 
333             name, type_name, class_name);
334         q_tree = gtk_tree_new();
335         add_subtree(tq, q_tree, ETT_NBNS_QD);
336
337         add_item_to_tree(q_tree, offset, name_len, "Name: %s", name);
338         offset += name_len;
339
340         add_item_to_tree(q_tree, offset, 2, "Type: %s", type_name);
341         offset += 2;
342
343         add_item_to_tree(q_tree, offset, 2, "Class: %s", class_name);
344         offset += 2;
345         
346         return dptr - data_start;
347 }
348
349 static void
350 nbns_add_nbns_flags(GtkWidget *nbns_tree, int offset, u_short flags,
351     int is_wack)
352 {
353         char buf[128+1];
354         GtkWidget *field_tree, *tf;
355         static const value_string rcode_vals[] = {
356                   { RCODE_NOERROR,   "No error"              },
357                   { RCODE_FMTERROR,  "Format error"          },
358                   { RCODE_SERVFAIL,  "Server failure"        },
359                   { RCODE_NAMEERROR, "Name error"            },
360                   { RCODE_NOTIMPL,   "Not implemented"       },
361                   { RCODE_REFUSED,   "Refused"               },
362                   { RCODE_ACTIVE,    "Name is active"        },
363                   { RCODE_CONFLICT,  "Name is in conflict"   },
364                   { 0,               NULL                    }
365         };
366
367         strcpy(buf, val_to_str(flags & F_OPCODE, opcode_vals,
368                                 "Unknown operation"));
369         if (flags & F_RESPONSE && !is_wack) {
370                 strcat(buf, " response");
371                 strcat(buf, ", ");
372                 strcat(buf, val_to_str(flags & F_RCODE, rcode_vals,
373                     "Unknown error"));
374         }
375         tf = add_item_to_tree(nbns_tree, offset, 2,
376                         "Flags: 0x%04x (%s)", flags, buf);
377         field_tree = gtk_tree_new();
378         add_subtree(tf, field_tree, ETT_NBNS_FLAGS);
379         add_item_to_tree(field_tree, offset, 2, "%s",
380                         decode_boolean_bitfield(flags, F_RESPONSE,
381                                 2*8, "Response", "Query"));
382         add_item_to_tree(field_tree, offset, 2, "%s",
383                         decode_enumerated_bitfield(flags, F_OPCODE,
384                                 2*8, opcode_vals, "%s"));
385         if (flags & F_RESPONSE) {
386                 add_item_to_tree(field_tree, offset, 2,
387                         "%s",
388                         decode_boolean_bitfield(flags, F_AUTHORITATIVE,
389                                 2*8,
390                                 "Server is an authority for domain",
391                                 "Server isn't an authority for domain"));
392         }
393         add_item_to_tree(field_tree, offset, 2, "%s",
394                         decode_boolean_bitfield(flags, F_TRUNCATED,
395                                 2*8,
396                                 "Message is truncated",
397                                 "Message is not truncated"));
398         add_item_to_tree(field_tree, offset, 2, "%s",
399                         decode_boolean_bitfield(flags, F_RECDESIRED,
400                                 2*8,
401                                 "Do query recursively",
402                                 "Don't do query recursively"));
403         if (flags & F_RESPONSE) {
404                 add_item_to_tree(field_tree, offset, 2,
405                         "%s",
406                         decode_boolean_bitfield(flags, F_RECAVAIL,
407                                 2*8,
408                                 "Server can do recursive queries",
409                                 "Server can't do recursive queries"));
410         }
411         add_item_to_tree(field_tree, offset, 2, "%s",
412                         decode_boolean_bitfield(flags, F_BROADCAST,
413                                 2*8,
414                                 "Broadcast packet",
415                                 "Not a broadcast packet"));
416         if (flags & F_RESPONSE && !is_wack) {
417                 add_item_to_tree(field_tree, offset, 2,
418                         "%s",
419                         decode_enumerated_bitfield(flags, F_RCODE,
420                                 2*8,
421                                 rcode_vals, "%s"));
422         }
423 }
424
425 static void
426 nbns_add_nb_flags(GtkWidget *rr_tree, int offset, u_short flags)
427 {
428         char buf[128+1];
429         GtkWidget *field_tree, *tf;
430         static const value_string nb_flags_ont_vals[] = {
431                   { NB_FLAGS_ONT_B_NODE, "B-node" },
432                   { NB_FLAGS_ONT_P_NODE, "P-node" },
433                   { NB_FLAGS_ONT_M_NODE, "M-node" },
434                   { NB_FLAGS_ONT_H_NODE, "H-node" },
435                   { 0,                   NULL     }
436         };
437
438         strcpy(buf, val_to_str(flags & NB_FLAGS_ONT, nb_flags_ont_vals,
439             "Unknown"));
440         strcat(buf, ", ");
441         if (flags & NB_FLAGS_G)
442                 strcat(buf, "group");
443         else
444                 strcat(buf, "unique");
445         tf = add_item_to_tree(rr_tree, offset, 2, "Flags: 0x%x (%s)", flags,
446                         buf);
447         field_tree = gtk_tree_new();
448         add_subtree(tf, field_tree, ETT_NBNS_NB_FLAGS);
449         add_item_to_tree(field_tree, offset, 2, "%s",
450                         decode_boolean_bitfield(flags, NB_FLAGS_G,
451                                 2*8,
452                                 "Group name",
453                                 "Unique name"));
454         add_item_to_tree(field_tree, offset, 2, "%s",
455                         decode_enumerated_bitfield(flags, NB_FLAGS_ONT,
456                                 2*8, nb_flags_ont_vals, "%s"));
457 }
458
459 static void
460 nbns_add_name_flags(GtkWidget *rr_tree, int offset, u_short flags)
461 {
462         char buf[128+1];
463         GtkWidget *field_tree, *tf;
464         static const value_string name_flags_ont_vals[] = {
465                   { NAME_FLAGS_ONT_B_NODE, "B-node" },
466                   { NAME_FLAGS_ONT_P_NODE, "P-node" },
467                   { NAME_FLAGS_ONT_M_NODE, "M-node" },
468                   { 0,                     NULL     }
469         };
470
471         strcpy(buf, val_to_str(flags & NAME_FLAGS_ONT, name_flags_ont_vals,
472             "Unknown"));
473         strcat(buf, ", ");
474         if (flags & NAME_FLAGS_G)
475                 strcat(buf, "group");
476         else
477                 strcat(buf, "unique");
478         if (flags & NAME_FLAGS_DRG)
479                 strcat(buf, ", being deregistered");
480         if (flags & NAME_FLAGS_CNF)
481                 strcat(buf, ", in conflict");
482         if (flags & NAME_FLAGS_ACT)
483                 strcat(buf, ", active");
484         if (flags & NAME_FLAGS_PRM)
485                 strcat(buf, ", permanent node name");
486         tf = add_item_to_tree(rr_tree, offset, 2, "Name flags: 0x%x (%s)",
487                         flags, buf);
488         field_tree = gtk_tree_new();
489         add_subtree(tf, field_tree, ETT_NBNS_NAME_FLAGS);
490         add_item_to_tree(field_tree, offset, 2, "%s",
491                         decode_boolean_bitfield(flags, NAME_FLAGS_G,
492                                 2*8,
493                                 "Group name",
494                                 "Unique name"));
495         add_item_to_tree(field_tree, offset, 2, "%s",
496                         decode_enumerated_bitfield(flags, NAME_FLAGS_ONT,
497                                 2*8, name_flags_ont_vals, "%s"));
498         add_item_to_tree(field_tree, offset, 2, "%s",
499                         decode_boolean_bitfield(flags, NAME_FLAGS_DRG,
500                                 2*8,
501                                 "Name is being deregistered",
502                                 "Name is not being deregistered"));
503         add_item_to_tree(field_tree, offset, 2, "%s",
504                         decode_boolean_bitfield(flags, NAME_FLAGS_CNF,
505                                 2*8,
506                                 "Name is in conflict",
507                                 "Name is not in conflict"));
508         add_item_to_tree(field_tree, offset, 2, "%s",
509                         decode_boolean_bitfield(flags, NAME_FLAGS_ACT,
510                                 2*8,
511                                 "Name is active",
512                                 "Name is not active"));
513         add_item_to_tree(field_tree, offset, 2, "%s",
514                         decode_boolean_bitfield(flags, NAME_FLAGS_PRM,
515                                 2*8,
516                                 "Permanent node name",
517                                 "Not permanent node name"));
518 }
519
520 static int
521 dissect_nbns_answer(const u_char *nbns_data_ptr, const u_char *pd, int offset,
522     GtkWidget *nbns_tree, int opcode)
523 {
524         int len;
525         char name[MAXDNAME];
526         int name_len;
527         int type;
528         int class;
529         char *class_name;
530         char *type_name;
531         const u_char *dptr;
532         const u_char *data_start;
533         u_int ttl;
534         u_short data_len;
535         u_short flags;
536         GtkWidget *rr_tree, *trr;
537
538         data_start = dptr = pd + offset;
539
540         len = get_nbns_name_type_class(nbns_data_ptr, pd, offset, name,
541             &name_len, &type, &class);
542         dptr += len;
543
544         type_name = nbns_type_name(type);
545         class_name = dns_class_name(class);
546
547         ttl = pntohl(dptr);
548         dptr += 4;
549
550         data_len = pntohs(dptr);
551         dptr += 2;
552
553         switch (type) {
554         case T_NB:              /* "NB" record */
555                 trr = add_item_to_tree(nbns_tree, offset,
556                     (dptr - data_start) + data_len,
557                     "%s: type %s, class %s",
558                     name, type_name, class_name);
559                 rr_tree = add_rr_to_tree(trr, ETT_NBNS_RR, offset, name,
560                     name_len, type_name, class_name, ttl, data_len);
561                 offset += (dptr - data_start);
562                 while (data_len > 0) {
563                         if (opcode == OPCODE_WACK) {
564                                 /* WACK response.  This doesn't contain the
565                                  * same type of RR data as other T_NB
566                                  * responses.  */
567                                 if (data_len < 2) {
568                                         add_item_to_tree(rr_tree, offset,
569                                             data_len, "(incomplete entry)");
570                                         break;
571                                 }
572                                 flags = pntohs(dptr);
573                                 dptr += 2;
574                                 nbns_add_nbns_flags(rr_tree, offset, flags, 1);
575                                 offset += 2;
576                                 data_len -= 2;
577                         } else {
578                                 if (data_len < 2) {
579                                         add_item_to_tree(rr_tree, offset,
580                                             data_len, "(incomplete entry)");
581                                         break;
582                                 }
583                                 flags = pntohs(dptr);
584                                 dptr += 2;
585                                 nbns_add_nb_flags(rr_tree, offset, flags);
586                                 offset += 2;
587                                 data_len -= 2;
588
589                                 if (data_len < 4) {
590                                         add_item_to_tree(rr_tree, offset,
591                                             data_len, "(incomplete entry)");
592                                         break;
593                                 }
594                                 add_item_to_tree(rr_tree, offset, 4,
595                                     "Addr: %s",
596                                     ip_to_str((guint8 *)dptr));
597                                 dptr += 4;
598                                 offset += 4;
599                                 data_len -= 4;
600                         }
601                 }
602                 break;
603
604         case T_NBSTAT:  /* "NBSTAT" record */
605                 {
606                         u_int num_names;
607                         char nbname[16+4+1];    /* 4 for [<last char>] */
608                         u_short name_flags;
609                         
610                         trr = add_item_to_tree(nbns_tree, offset,
611                             (dptr - data_start) + data_len,
612                             "%s: type %s, class %s",
613                             name, type_name, class_name);
614                         rr_tree = add_rr_to_tree(trr, ETT_NBNS_RR, offset, name,
615                             name_len, type_name, class_name, ttl, data_len);
616                         offset += (dptr - data_start);
617                         if (data_len < 1) {
618                                 add_item_to_tree(rr_tree, offset,
619                                     data_len, "(incomplete entry)");
620                                 break;
621                         }
622                         num_names = *dptr;
623                         dptr += 1;
624                         add_item_to_tree(rr_tree, offset, 2,
625                             "Number of names: %u", num_names);
626                         offset += 1;
627
628                         while (num_names != 0) {
629                                 if (data_len < 16) {
630                                         add_item_to_tree(rr_tree, offset,
631                                             data_len, "(incomplete entry)");
632                                         goto out;
633                                 }
634                                 memcpy(nbname, dptr, 16);
635                                 dptr += 16;
636                                 canonicalize_netbios_name(nbname);
637                                 add_item_to_tree(rr_tree, offset, 16,
638                                     "Name: %s", nbname);
639                                 offset += 16;
640                                 data_len -= 16;
641
642                                 if (data_len < 2) {
643                                         add_item_to_tree(rr_tree, offset,
644                                             data_len, "(incomplete entry)");
645                                         goto out;
646                                 }
647                                 name_flags = pntohs(dptr);
648                                 dptr += 2;
649                                 nbns_add_name_flags(rr_tree, offset, name_flags);
650                                 offset += 2;
651                                 data_len -= 2;
652
653                                 num_names--;
654                         }
655
656                         if (data_len < 6) {
657                                 add_item_to_tree(rr_tree, offset,
658                                     data_len, "(incomplete entry)");
659                                 break;
660                         }
661                         add_item_to_tree(rr_tree, offset, 6,
662                             "Unit ID: %s",
663                             ether_to_str((guint8 *)dptr));
664                         dptr += 6;
665                         offset += 6;
666                         data_len -= 6;
667
668                         if (data_len < 1) {
669                                 add_item_to_tree(rr_tree, offset,
670                                     data_len, "(incomplete entry)");
671                                 break;
672                         }
673                         add_item_to_tree(rr_tree, offset, 1,
674                             "Jumpers: 0x%x", *dptr);
675                         dptr += 1;
676                         offset += 1;
677                         data_len -= 1;
678
679                         if (data_len < 1) {
680                                 add_item_to_tree(rr_tree, offset,
681                                     data_len, "(incomplete entry)");
682                                 break;
683                         }
684                         add_item_to_tree(rr_tree, offset, 1,
685                             "Test result: 0x%x", *dptr);
686                         dptr += 1;
687                         offset += 1;
688                         data_len -= 1;
689
690                         if (data_len < 2) {
691                                 add_item_to_tree(rr_tree, offset,
692                                     data_len, "(incomplete entry)");
693                                 break;
694                         }
695                         add_item_to_tree(rr_tree, offset, 2,
696                             "Version number: 0x%x", pntohs(dptr));
697                         dptr += 2;
698                         offset += 2;
699                         data_len -= 2;
700
701                         if (data_len < 2) {
702                                 add_item_to_tree(rr_tree, offset,
703                                     data_len, "(incomplete entry)");
704                                 break;
705                         }
706                         add_item_to_tree(rr_tree, offset, 2,
707                             "Period of statistics: 0x%x", pntohs(dptr));
708                         dptr += 2;
709                         offset += 2;
710                         data_len -= 2;
711
712                         if (data_len < 2) {
713                                 add_item_to_tree(rr_tree, offset,
714                                     data_len, "(incomplete entry)");
715                                 break;
716                         }
717                         add_item_to_tree(rr_tree, offset, 2,
718                             "Number of CRCs: %u", pntohs(dptr));
719                         dptr += 2;
720                         offset += 2;
721                         data_len -= 2;
722
723                         if (data_len < 2) {
724                                 add_item_to_tree(rr_tree, offset,
725                                     data_len, "(incomplete entry)");
726                                 break;
727                         }
728                         add_item_to_tree(rr_tree, offset, 2,
729                             "Number of alignment errors: %u", pntohs(dptr));
730                         dptr += 2;
731                         offset += 2;
732                         data_len -= 2;
733
734                         if (data_len < 2) {
735                                 add_item_to_tree(rr_tree, offset,
736                                     data_len, "(incomplete entry)");
737                                 break;
738                         }
739                         add_item_to_tree(rr_tree, offset, 2,
740                             "Number of collisions: %u", pntohs(dptr));
741                         dptr += 2;
742                         offset += 2;
743                         data_len -= 2;
744
745                         if (data_len < 2) {
746                                 add_item_to_tree(rr_tree, offset,
747                                     data_len, "(incomplete entry)");
748                                 break;
749                         }
750                         add_item_to_tree(rr_tree, offset, 2,
751                             "Number of send aborts: %u", pntohs(dptr));
752                         dptr += 2;
753                         offset += 2;
754                         data_len -= 2;
755
756                         if (data_len < 4) {
757                                 add_item_to_tree(rr_tree, offset,
758                                     data_len, "(incomplete entry)");
759                                 break;
760                         }
761                         add_item_to_tree(rr_tree, offset, 4,
762                             "Number of good sends: %u", pntohl(dptr));
763                         dptr += 4;
764                         offset += 4;
765                         data_len -= 4;
766
767                         if (data_len < 4) {
768                                 add_item_to_tree(rr_tree, offset,
769                                     data_len, "(incomplete entry)");
770                                 break;
771                         }
772                         add_item_to_tree(rr_tree, offset, 4,
773                             "Number of good receives: %u", pntohl(dptr));
774                         dptr += 4;
775                         offset += 4;
776                         data_len -= 4;
777
778                         if (data_len < 2) {
779                                 add_item_to_tree(rr_tree, offset,
780                                     data_len, "(incomplete entry)");
781                                 break;
782                         }
783                         add_item_to_tree(rr_tree, offset, 2,
784                             "Number of retransmits: %u", pntohs(dptr));
785                         dptr += 2;
786                         offset += 2;
787                         data_len -= 2;
788
789                         if (data_len < 2) {
790                                 add_item_to_tree(rr_tree, offset,
791                                     data_len, "(incomplete entry)");
792                                 break;
793                         }
794                         add_item_to_tree(rr_tree, offset, 2,
795                             "Number of no resource conditions: %u", pntohs(dptr));
796                         dptr += 2;
797                         offset += 2;
798                         data_len -= 2;
799
800                         if (data_len < 2) {
801                                 add_item_to_tree(rr_tree, offset,
802                                     data_len, "(incomplete entry)");
803                                 break;
804                         }
805                         add_item_to_tree(rr_tree, offset, 2,
806                             "Number of command blocks: %u", pntohs(dptr));
807                         dptr += 2;
808                         offset += 2;
809                         data_len -= 2;
810
811                         if (data_len < 2) {
812                                 add_item_to_tree(rr_tree, offset,
813                                     data_len, "(incomplete entry)");
814                                 break;
815                         }
816                         add_item_to_tree(rr_tree, offset, 2,
817                             "Number of pending sessions: %u", pntohs(dptr));
818                         dptr += 2;
819                         offset += 2;
820                         data_len -= 2;
821
822                         if (data_len < 2) {
823                                 add_item_to_tree(rr_tree, offset,
824                                     data_len, "(incomplete entry)");
825                                 break;
826                         }
827                         add_item_to_tree(rr_tree, offset, 2,
828                             "Max number of pending sessions: %u", pntohs(dptr));
829                         dptr += 2;
830                         offset += 2;
831
832                         add_item_to_tree(rr_tree, offset, 2,
833                             "Max total sessions possible: %u", pntohs(dptr));
834                         dptr += 2;
835                         offset += 2;
836                         data_len -= 2;
837
838                         if (data_len < 2) {
839                                 add_item_to_tree(rr_tree, offset,
840                                     data_len, "(incomplete entry)");
841                                 break;
842                         }
843                         add_item_to_tree(rr_tree, offset, 2,
844                             "Session data packet size: %u", pntohs(dptr));
845                         dptr += 2;
846                         offset += 2;
847                         data_len -= 2;
848                 }
849         out:
850                 break;
851
852         default:
853                 trr = add_item_to_tree(nbns_tree, offset,
854                     (dptr - data_start) + data_len,
855                     "%s: type %s, class %s",
856                     name, type_name, class_name);
857                 rr_tree = add_rr_to_tree(trr, ETT_NBNS_RR, offset, name,
858                     name_len, type_name, class_name, ttl, data_len);
859                 offset += (dptr - data_start);
860                 add_item_to_tree(rr_tree, offset, data_len, "Data");
861                 break;
862         }
863         dptr += data_len;
864         
865         return dptr - data_start;
866 }
867
868 static int
869 dissect_query_records(const u_char *nbns_data_ptr, int count, const u_char *pd, 
870     int cur_off, GtkWidget *nbns_tree)
871 {
872         int start_off;
873         GtkWidget *qatree, *ti;
874         
875         start_off = cur_off;
876         ti = add_item_to_tree(GTK_WIDGET(nbns_tree), 
877                         start_off, 0, "Queries");
878         qatree = gtk_tree_new();
879         add_subtree(ti, qatree, ETT_NBNS_QRY);
880         while (count-- > 0)
881                 cur_off += dissect_nbns_query(nbns_data_ptr, pd, cur_off, qatree);
882         set_item_len(ti, cur_off - start_off);
883
884         return cur_off - start_off;
885 }
886
887
888
889 static int
890 dissect_answer_records(const u_char *nbns_data_ptr, int count,
891     const u_char *pd, int cur_off, GtkWidget *nbns_tree, int opcode, char *name)
892 {
893         int start_off;
894         GtkWidget *qatree, *ti;
895         
896         start_off = cur_off;
897         ti = add_item_to_tree(GTK_WIDGET(nbns_tree),
898                         start_off, 0, name);
899         qatree = gtk_tree_new();
900         add_subtree(ti, qatree, ETT_NBNS_ANS);
901         while (count-- > 0)
902                 cur_off += dissect_nbns_answer(nbns_data_ptr, pd, cur_off,
903                                         qatree, opcode);
904         set_item_len(ti, cur_off - start_off);
905         return cur_off - start_off;
906 }
907
908 void
909 dissect_nbns(const u_char *pd, int offset, frame_data *fd, GtkTree *tree)
910 {
911         const u_char            *nbns_data_ptr;
912         GtkWidget               *nbns_tree, *ti;
913         guint16                 id, flags, quest, ans, auth, add;
914         int                     cur_off;
915
916         nbns_data_ptr = &pd[offset];
917
918         /* To do: check for runts, errs, etc. */
919         id    = pntohs(&pd[offset + NBNS_ID]);
920         flags = pntohs(&pd[offset + NBNS_FLAGS]);
921         quest = pntohs(&pd[offset + NBNS_QUEST]);
922         ans   = pntohs(&pd[offset + NBNS_ANS]);
923         auth  = pntohs(&pd[offset + NBNS_AUTH]);
924         add   = pntohs(&pd[offset + NBNS_ADD]);
925
926         if (check_col(fd, COL_PROTOCOL))
927                 col_add_str(fd, COL_PROTOCOL, "NBNS (UDP)");
928         if (check_col(fd, COL_INFO)) {
929                 col_add_fstr(fd, COL_INFO, "%s%s",
930                     val_to_str(flags & F_OPCODE, opcode_vals,
931                       "Unknown operation (%x)"),
932                     (flags & F_RESPONSE) ? " response" : "");
933         }
934
935         if (tree) {
936                 ti = add_item_to_tree(GTK_WIDGET(tree), offset, END_OF_FRAME,
937                                 "NetBIOS Name Service");
938                 nbns_tree = gtk_tree_new();
939                 add_subtree(ti, nbns_tree, ETT_NBNS);
940
941                 add_item_to_tree(nbns_tree, offset + NBNS_ID, 2,
942                                 "Transaction ID: 0x%04X", id);
943
944                 nbns_add_nbns_flags(nbns_tree, offset + NBNS_FLAGS, flags, 0);
945                 add_item_to_tree(nbns_tree, offset + NBNS_QUEST, 2,
946                                         "Questions: %d",
947                                         quest);
948                 add_item_to_tree(nbns_tree, offset + NBNS_ANS, 2,
949                                         "Answer RRs: %d",
950                                         ans);
951                 add_item_to_tree(nbns_tree, offset + NBNS_AUTH, 2,
952                                         "Authority RRs: %d",
953                                         auth);
954                 add_item_to_tree(nbns_tree, offset + NBNS_ADD, 2,
955                                         "Additional RRs: %d",
956                                         add);
957
958                 cur_off = offset + NBNS_HDRLEN;
959     
960                 if (quest > 0)
961                         cur_off += dissect_query_records(nbns_data_ptr,
962                                         quest, pd, cur_off, nbns_tree);
963
964                 if (ans > 0)
965                         cur_off += dissect_answer_records(nbns_data_ptr,
966                                         ans, pd, cur_off, nbns_tree,
967                                         flags & F_OPCODE,
968                                         "Answers");
969
970                 if (auth > 0)
971                         cur_off += dissect_answer_records(nbns_data_ptr,
972                                         auth, pd, cur_off, nbns_tree, 
973                                         flags & F_OPCODE,
974                                         "Authoritative nameservers");
975
976                 if (add > 0)
977                         cur_off += dissect_answer_records(nbns_data_ptr,
978                                         add, pd, cur_off, nbns_tree, 
979                                         flags & F_OPCODE,
980                                         "Additional records");
981         }
982 }
983
984
985 void
986 dissect_nbdgm(const u_char *pd, int offset, frame_data *fd, GtkTree *tree)
987 {
988         GtkWidget               *nbdgm_tree, *ti;
989         struct nbdgm_header     header;
990         int                     flags;
991         int                     message_index;
992
993         char *message[] = {
994                 "Unknown",
995                 "Direct_unique datagram",
996                 "Direct_group datagram",
997                 "Broadcast datagram",
998                 "Datagram error",
999                 "Datagram query request",
1000                 "Datagram positive query response",
1001                 "Datagram negative query response"
1002         };
1003
1004         char *node[] = {
1005                 "B node",
1006                 "P node",
1007                 "M node",
1008                 "NBDD"
1009         };
1010
1011         static value_string error_codes[] = {
1012                 { 0x82, "Destination name not present" },
1013                 { 0x83, "Invalid source name format" },
1014                 { 0x84, "Invalid destination name format" },
1015                 { 0x00, NULL }
1016         };
1017
1018         char *yesno[] = { "No", "Yes" };
1019
1020         char name[32];
1021         int len;
1022
1023         header.msg_type = pd[offset];
1024         
1025         flags = pd[offset+1];
1026         header.flags.more = flags & 1;
1027         header.flags.first = (flags & 2) >> 1;
1028         header.flags.node_type = (flags & 12) >> 2;
1029
1030         header.dgm_id = pntohs(&pd[offset+2]);
1031         memcpy(&header.src_ip, &pd[offset+4], 4);
1032         header.src_port = pntohs(&pd[offset+8]);
1033
1034         if (header.msg_type == 0x10 ||
1035                         header.msg_type == 0x11 || header.msg_type == 0x12) {
1036                 header.dgm_length = pntohs(&pd[offset+10]);
1037                 header.pkt_offset = pntohs(&pd[offset+12]);
1038         }
1039         else if (header.msg_type == 0x13) {
1040                 header.error_code = pntohs(&pd[offset+10]);
1041         }
1042
1043         message_index = header.msg_type - 0x0f;
1044         if (message_index < 1 || message_index > 8) {
1045                 message_index = 0;
1046         }
1047
1048         if (check_col(fd, COL_PROTOCOL))
1049                 col_add_str(fd, COL_PROTOCOL, "NBDS (UDP)");
1050         if (check_col(fd, COL_INFO)) {
1051                 col_add_fstr(fd, COL_INFO, "%s", message[message_index]);
1052         }
1053
1054         if (tree) {
1055                 ti = add_item_to_tree(GTK_WIDGET(tree), offset, header.dgm_length,
1056                                 "NetBIOS Datagram Service");
1057                 nbdgm_tree = gtk_tree_new();
1058                 add_subtree(ti, nbdgm_tree, ETT_NBDGM);
1059
1060                 add_item_to_tree(nbdgm_tree, offset, 1, "Message Type: %s",
1061                                 message[message_index]);
1062                 add_item_to_tree(nbdgm_tree, offset+1, 1, "More fragments follow: %s",
1063                                 yesno[header.flags.more]);
1064                 add_item_to_tree(nbdgm_tree, offset+1, 1, "This is first fragment: %s",
1065                                 yesno[header.flags.first]);
1066                 add_item_to_tree(nbdgm_tree, offset+1, 1, "Node Type: %s",
1067                                 node[header.flags.node_type]);
1068
1069                 add_item_to_tree(nbdgm_tree, offset+2, 2, "Datagram ID: 0x%04X",
1070                                 header.dgm_id);
1071                 add_item_to_tree(nbdgm_tree, offset+4, 4, "Source IP: %s",
1072                                 ip_to_str((guint8 *)&header.src_ip));
1073                 add_item_to_tree(nbdgm_tree, offset+8, 2, "Source Port: %d",
1074                                 header.src_port);
1075
1076                 offset += 10;
1077
1078                 if (header.msg_type == 0x10 ||
1079                                 header.msg_type == 0x11 || header.msg_type == 0x12) {
1080
1081                         add_item_to_tree(nbdgm_tree, offset, 2,
1082                                         "Datagram length: %d bytes", header.dgm_length);
1083                         add_item_to_tree(nbdgm_tree, offset+2, 2,
1084                                         "Packet offset: %d bytes", header.pkt_offset);
1085
1086                         offset += 4;
1087
1088                         /* Source name */
1089                         len = get_nbns_name(&pd[offset], pd, offset, name);
1090
1091                         add_item_to_tree(nbdgm_tree, offset, len, "Source name: %s",
1092                                         name);
1093                         offset += len;
1094
1095                         /* Destination name */
1096                         len = get_nbns_name(&pd[offset], pd, offset, name);
1097
1098                         add_item_to_tree(nbdgm_tree, offset, len, "Destination name: %s",
1099                                         name);
1100                         offset += len;
1101
1102                         /* here we can pass the packet off to the next protocol */
1103                         dissect_data(pd, offset, fd, GTK_TREE(nbdgm_tree));
1104                 }
1105                 else if (header.msg_type == 0x13) {
1106                         add_item_to_tree(nbdgm_tree, offset, 1, "Error code: %s",
1107                                 val_to_str(header.error_code, error_codes, "Unknown (0x%x)"));
1108                 }
1109                 else if (header.msg_type == 0x14 ||
1110                                 header.msg_type == 0x15 || header.msg_type == 0x16) {
1111                         /* Destination name */
1112                         len = get_nbns_name(&pd[offset], pd, offset, name);
1113
1114                         add_item_to_tree(nbdgm_tree, offset, len, "Destination name: %s",
1115                                         name);
1116                 }
1117         }
1118 }