Added NetBIOS datagram support (over UDP, as per RFC 1002).
[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.8 1998/11/20 05:54:08 gram 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 <memory.h>
36
37 #ifdef HAVE_SYS_TYPES_H
38 # include <sys/types.h>
39 #endif
40
41 #ifdef HAVE_NETINET_IN_H
42 # include <netinet/in.h>
43 #endif
44
45 #include "ethereal.h"
46 #include "packet.h"
47 #include "packet-dns.h"
48
49 /* Packet structure taken from RFC 1002. See also RFC 1001.
50  * The Samba source code, specifically nmblib.c, also helps a lot. */
51
52 struct nbns_header {
53
54         guint16         name_tran_id;
55         guint8          r;
56         guint8          opcode;
57         struct {
58                 guint8  bcast;
59                 guint8  recursion_available;
60                 guint8  recursion_desired;
61                 guint8  trunc;
62                 guint8  authoritative;
63         } nm_flags;
64         guint8          rcode;
65         guint16         qdcount;
66         guint16         ancount;
67         guint16         nscount;
68         guint16         arcount;
69 };
70
71 /* type values  */
72 #define T_NB            32              /* NetBIOS name service RR */
73 #define T_NBSTAT        33              /* NetBIOS node status RR */
74
75 /* NetBIOS datagram packet, from RFC 1002, page 32 */
76 struct nbdgm_header {
77         guint8          msg_type;
78         struct {
79                 guint8  more;
80                 guint8  first;
81                 guint8  node_type;
82         } flags;
83         guint16         dgm_id;
84         guint32         src_ip;
85         guint16         src_port;
86
87         /* For packets with data */
88         guint16         dgm_length;
89         guint16         pkt_offset;
90
91         /* For error packets */
92         guint8          error_code;
93 };
94
95
96 static char *
97 nbns_type_name (int type)
98 {
99         switch (type) {
100         case T_NB:
101                 return "NB";
102         case T_NBSTAT:
103                 return "NBSTAT";
104         }
105         
106         return "unknown";
107 }
108
109 /* "Canonicalize" a 16-character NetBIOS name by:
110  *
111  *      removing and saving the last byte;
112  *
113  *      stripping trailing blanks;
114  *
115  *      appending the trailing byte, as a hex number, in square brackets. */
116 static char *
117 canonicalize_netbios_name(char *nbname)
118 {
119         char *pnbname;
120         u_char lastchar;
121
122         /* Get the last character of the name, as it's a special number
123          * indicating the type of the name, rather than part of the name
124          * *per se*. */
125         pnbname = nbname + 15;  /* point to the 16th character */
126         lastchar = *(unsigned char *)pnbname;
127
128         /* Now strip off any trailing blanks used to pad it to
129          * 16 bytes. */
130         while (pnbname > &nbname[0]) {
131                 if (*(pnbname - 1) != ' ')
132                         break;          /* found non-blank character */
133                 pnbname--;              /* blank - skip over it */
134         }
135
136         /* Replace the last character with its hex value, in square
137          * brackets, to make it easier to tell what it is. */
138         sprintf(pnbname, "[%02X]", lastchar);
139         pnbname += 4;
140         return pnbname;
141 }
142
143 static int
144 get_nbns_name_type_class(const u_char *nbns_data_ptr, const u_char *pd,
145     int offset, char *name_ret, int *name_len_ret, int *type_ret,
146     int *class_ret)
147 {
148         int len;
149         int name_len;
150         int type;
151         int class;
152         char name[MAXDNAME];
153         char nbname[MAXDNAME+4];        /* 4 for [<last char>] */
154         char *pname, *pnbname, cname, cnbname;
155         const u_char *pd_save;
156
157         name_len = get_dns_name(nbns_data_ptr, pd, offset, name, sizeof(name));
158         pd += offset;
159         pd_save = pd;
160         pd += name_len;
161         
162         type = pntohs(pd);
163         pd += 2;
164         class = pntohs(pd);
165         pd += 2;
166
167         /* OK, now undo the first-level encoding. */
168         pname = &name[0];
169         pnbname = &nbname[0];
170         for (;;) {
171                 /* Every two characters of the first level-encoded name
172                  * turn into one character in the decoded name. */
173                 cname = *pname;
174                 if (cname == '\0')
175                         break;          /* no more characters */
176                 if (cname == '.')
177                         break;          /* scope ID follows */
178                 if (cname < 'A' || cname > 'Z') {
179                         /* Not legal. */
180                         strcpy(nbname,
181                             "Illegal NetBIOS name (character not between A and Z in first-level encoding)");
182                         goto bad;
183                 }
184                 cname -= 'A';
185                 cnbname = cname << 4;
186                 pname++;
187
188                 cname = *pname;
189                 if (cname == '\0' || cname == '.') {
190                         /* No more characters in the name - but we're in
191                          * the middle of a pair.  Not legal. */
192                         strcpy(nbname,
193                             "Illegal NetBIOS name (odd number of bytes)");
194                         goto bad;
195                 }
196                 if (cname < 'A' || cname > 'Z') {
197                         /* Not legal. */
198                         strcpy(nbname,
199                             "Illegal NetBIOS name (character not between A and Z in first-level encoding)");
200                         goto bad;
201                 }
202                 cname -= 'A';
203                 cnbname |= cname;
204                 pname++;
205
206                 /* Store the character. */
207                 *pnbname++ = cnbname;
208         }
209
210         /* NetBIOS names are supposed to be exactly 16 bytes long. */
211         if (pnbname - nbname == 16) {
212                 /* This one is; canonicalize its name. */
213                 pnbname = canonicalize_netbios_name(nbname);
214         } else {
215                 sprintf(nbname, "Illegal NetBIOS name (%ld bytes long)",
216                     (long)(pnbname - nbname));
217                 goto bad;
218         }
219         if (cname == '.') {
220                 /* We have a scope ID, starting at "pname"; append that to
221                  * the decoded host name. */
222                 strcpy(pnbname, pname);
223         } else {
224                 /* Terminate the decoded host name. */
225                 *pnbname = '\0';
226         }
227
228 bad:
229         strcpy (name_ret, nbname);
230         *type_ret = type;
231         *class_ret = class;
232         *name_len_ret = name_len;
233
234         len = pd - pd_save;
235         return len;
236 }
237
238
239 static int
240 dissect_nbns_query(const u_char *nbns_data_ptr, const u_char *pd, int offset,
241     GtkWidget *nbns_tree)
242 {
243         int len;
244         char name[MAXDNAME];
245         int name_len;
246         int type;
247         int class;
248         char *class_name;
249         char *type_name;
250         const u_char *dptr;
251         const u_char *data_start;
252         GtkWidget *q_tree, *tq;
253
254         data_start = dptr = pd + offset;
255
256         len = get_nbns_name_type_class(nbns_data_ptr, pd, offset, name,
257             &name_len, &type, &class);
258         dptr += len;
259
260         type_name = nbns_type_name(type);
261         class_name = dns_class_name(class);
262
263         tq = add_item_to_tree(nbns_tree, offset, len, "%s: type %s, class %s", 
264             name, type_name, class_name);
265         q_tree = gtk_tree_new();
266         add_subtree(tq, q_tree, ETT_NBNS_QD);
267
268         add_item_to_tree(q_tree, offset, name_len, "Name: %s", name);
269         offset += name_len;
270
271         add_item_to_tree(q_tree, offset, 2, "Type: %s", type_name);
272         offset += 2;
273
274         add_item_to_tree(q_tree, offset, 2, "Class: %s", class_name);
275         offset += 2;
276         
277         return dptr - data_start;
278 }
279
280
281 static int
282 dissect_nbns_answer(const u_char *nbns_data_ptr, const u_char *pd, int offset,
283     GtkWidget *nbns_tree, int opcode)
284 {
285         int len;
286         char name[MAXDNAME];
287         int name_len;
288         int type;
289         int class;
290         char *class_name;
291         char *type_name;
292         const u_char *dptr;
293         const u_char *data_start;
294         u_int ttl;
295         u_short data_len;
296         u_short flags;
297         GtkWidget *rr_tree, *trr;
298
299         data_start = dptr = pd + offset;
300
301         len = get_nbns_name_type_class(nbns_data_ptr, pd, offset, name,
302             &name_len, &type, &class);
303         dptr += len;
304
305         type_name = nbns_type_name(type);
306         class_name = dns_class_name(class);
307
308         ttl = pntohl(dptr);
309         dptr += 4;
310
311         data_len = pntohs(dptr);
312         dptr += 2;
313
314         switch (type) {
315         case T_NB:              /* "NB" record */
316                 trr = add_item_to_tree(nbns_tree, offset,
317                     (dptr - data_start) + data_len,
318                     "%s: type %s, class %s",
319                     name, type_name, class_name);
320                 rr_tree = add_rr_to_tree(trr, ETT_NBNS_RR, offset, name,
321                     name_len, type_name, class_name, ttl, data_len);
322                 offset += (dptr - data_start);
323                 while (data_len > 0) {
324                         if (opcode == 0x7) {
325                                 /* WACK response.  This doesn't contain the
326                                  * same type of RR data as other T_NB
327                                  * responses.  */
328                                 if (data_len < 2) {
329                                         add_item_to_tree(rr_tree, offset,
330                                             data_len, "(incomplete entry)");
331                                         break;
332                                 }
333                                 flags = pntohs(dptr);
334                                 dptr += 2;
335                                 add_item_to_tree(rr_tree, offset, 2,
336                                     "Flags: 0x%x", flags);
337                                 offset += 2;
338                                 data_len -= 2;
339                         } else {
340                                 if (data_len < 2) {
341                                         add_item_to_tree(rr_tree, offset,
342                                             data_len, "(incomplete entry)");
343                                         break;
344                                 }
345                                 flags = pntohs(dptr);
346                                 dptr += 2;
347                                 add_item_to_tree(rr_tree, offset, 2,
348                                     "Flags: 0x%x", flags);
349                                 offset += 2;
350                                 data_len -= 2;
351
352                                 if (data_len < 4) {
353                                         add_item_to_tree(rr_tree, offset,
354                                             data_len, "(incomplete entry)");
355                                         break;
356                                 }
357                                 add_item_to_tree(rr_tree, offset, 4,
358                                     "Addr: %s",
359                                     ip_to_str((guint8 *)dptr));
360                                 dptr += 4;
361                                 offset += 4;
362                                 data_len -= 4;
363                         }
364                 }
365                 break;
366
367         case T_NBSTAT:  /* "NBSTAT" record */
368                 {
369                         u_int num_names;
370                         char nbname[16+4+1];    /* 4 for [<last char>] */
371                         u_short name_flags;
372                         
373                         trr = add_item_to_tree(nbns_tree, offset,
374                             (dptr - data_start) + data_len,
375                             "%s: type %s, class %s",
376                             name, type_name, class_name);
377                         rr_tree = add_rr_to_tree(trr, ETT_NBNS_RR, offset, name,
378                             name_len, type_name, class_name, ttl, data_len);
379                         offset += (dptr - data_start);
380                         if (data_len < 1) {
381                                 add_item_to_tree(rr_tree, offset,
382                                     data_len, "(incomplete entry)");
383                                 break;
384                         }
385                         num_names = *dptr;
386                         dptr += 1;
387                         add_item_to_tree(rr_tree, offset, 2,
388                             "Number of names: %u", num_names);
389                         offset += 1;
390
391                         while (num_names != 0) {
392                                 if (data_len < 16) {
393                                         add_item_to_tree(rr_tree, offset,
394                                             data_len, "(incomplete entry)");
395                                         goto out;
396                                 }
397                                 memcpy(nbname, dptr, 16);
398                                 dptr += 16;
399                                 canonicalize_netbios_name(nbname);
400                                 add_item_to_tree(rr_tree, offset, 16,
401                                     "Name: %s", nbname);
402                                 offset += 16;
403                                 data_len -= 16;
404
405                                 if (data_len < 2) {
406                                         add_item_to_tree(rr_tree, offset,
407                                             data_len, "(incomplete entry)");
408                                         goto out;
409                                 }
410                                 name_flags = pntohs(dptr);
411                                 dptr += 2;
412                                 add_item_to_tree(rr_tree, offset, 2,
413                                     "Name flags: 0x%x", name_flags);
414                                 offset += 2;
415                                 data_len -= 2;
416
417                                 num_names--;
418                         }
419
420                         if (data_len < 6) {
421                                 add_item_to_tree(rr_tree, offset,
422                                     data_len, "(incomplete entry)");
423                                 break;
424                         }
425                         add_item_to_tree(rr_tree, offset, 6,
426                             "Unit ID: %s",
427                             ether_to_str((guint8 *)dptr));
428                         dptr += 6;
429                         offset += 6;
430                         data_len -= 6;
431
432                         if (data_len < 1) {
433                                 add_item_to_tree(rr_tree, offset,
434                                     data_len, "(incomplete entry)");
435                                 break;
436                         }
437                         add_item_to_tree(rr_tree, offset, 1,
438                             "Jumpers: 0x%x", *dptr);
439                         dptr += 1;
440                         offset += 1;
441                         data_len -= 1;
442
443                         if (data_len < 1) {
444                                 add_item_to_tree(rr_tree, offset,
445                                     data_len, "(incomplete entry)");
446                                 break;
447                         }
448                         add_item_to_tree(rr_tree, offset, 1,
449                             "Test result: 0x%x", *dptr);
450                         dptr += 1;
451                         offset += 1;
452                         data_len -= 1;
453
454                         if (data_len < 2) {
455                                 add_item_to_tree(rr_tree, offset,
456                                     data_len, "(incomplete entry)");
457                                 break;
458                         }
459                         add_item_to_tree(rr_tree, offset, 2,
460                             "Version number: 0x%x", pntohs(dptr));
461                         dptr += 2;
462                         offset += 2;
463                         data_len -= 2;
464
465                         if (data_len < 2) {
466                                 add_item_to_tree(rr_tree, offset,
467                                     data_len, "(incomplete entry)");
468                                 break;
469                         }
470                         add_item_to_tree(rr_tree, offset, 2,
471                             "Period of statistics: 0x%x", pntohs(dptr));
472                         dptr += 2;
473                         offset += 2;
474                         data_len -= 2;
475
476                         if (data_len < 2) {
477                                 add_item_to_tree(rr_tree, offset,
478                                     data_len, "(incomplete entry)");
479                                 break;
480                         }
481                         add_item_to_tree(rr_tree, offset, 2,
482                             "Number of CRCs: %u", pntohs(dptr));
483                         dptr += 2;
484                         offset += 2;
485                         data_len -= 2;
486
487                         if (data_len < 2) {
488                                 add_item_to_tree(rr_tree, offset,
489                                     data_len, "(incomplete entry)");
490                                 break;
491                         }
492                         add_item_to_tree(rr_tree, offset, 2,
493                             "Number of alignment errors: %u", pntohs(dptr));
494                         dptr += 2;
495                         offset += 2;
496                         data_len -= 2;
497
498                         if (data_len < 2) {
499                                 add_item_to_tree(rr_tree, offset,
500                                     data_len, "(incomplete entry)");
501                                 break;
502                         }
503                         add_item_to_tree(rr_tree, offset, 2,
504                             "Number of collisions: %u", pntohs(dptr));
505                         dptr += 2;
506                         offset += 2;
507                         data_len -= 2;
508
509                         if (data_len < 2) {
510                                 add_item_to_tree(rr_tree, offset,
511                                     data_len, "(incomplete entry)");
512                                 break;
513                         }
514                         add_item_to_tree(rr_tree, offset, 2,
515                             "Number of send aborts: %u", pntohs(dptr));
516                         dptr += 2;
517                         offset += 2;
518                         data_len -= 2;
519
520                         if (data_len < 4) {
521                                 add_item_to_tree(rr_tree, offset,
522                                     data_len, "(incomplete entry)");
523                                 break;
524                         }
525                         add_item_to_tree(rr_tree, offset, 4,
526                             "Number of good sends: %u", pntohl(dptr));
527                         dptr += 4;
528                         offset += 4;
529                         data_len -= 4;
530
531                         if (data_len < 4) {
532                                 add_item_to_tree(rr_tree, offset,
533                                     data_len, "(incomplete entry)");
534                                 break;
535                         }
536                         add_item_to_tree(rr_tree, offset, 4,
537                             "Number of good receives: %u", pntohl(dptr));
538                         dptr += 4;
539                         offset += 4;
540                         data_len -= 4;
541
542                         if (data_len < 2) {
543                                 add_item_to_tree(rr_tree, offset,
544                                     data_len, "(incomplete entry)");
545                                 break;
546                         }
547                         add_item_to_tree(rr_tree, offset, 2,
548                             "Number of retransmits: %u", pntohs(dptr));
549                         dptr += 2;
550                         offset += 2;
551                         data_len -= 2;
552
553                         if (data_len < 2) {
554                                 add_item_to_tree(rr_tree, offset,
555                                     data_len, "(incomplete entry)");
556                                 break;
557                         }
558                         add_item_to_tree(rr_tree, offset, 2,
559                             "Number of no resource conditions: %u", pntohs(dptr));
560                         dptr += 2;
561                         offset += 2;
562                         data_len -= 2;
563
564                         if (data_len < 2) {
565                                 add_item_to_tree(rr_tree, offset,
566                                     data_len, "(incomplete entry)");
567                                 break;
568                         }
569                         add_item_to_tree(rr_tree, offset, 2,
570                             "Number of command blocks: %u", pntohs(dptr));
571                         dptr += 2;
572                         offset += 2;
573                         data_len -= 2;
574
575                         if (data_len < 2) {
576                                 add_item_to_tree(rr_tree, offset,
577                                     data_len, "(incomplete entry)");
578                                 break;
579                         }
580                         add_item_to_tree(rr_tree, offset, 2,
581                             "Number of pending sessions: %u", pntohs(dptr));
582                         dptr += 2;
583                         offset += 2;
584                         data_len -= 2;
585
586                         if (data_len < 2) {
587                                 add_item_to_tree(rr_tree, offset,
588                                     data_len, "(incomplete entry)");
589                                 break;
590                         }
591                         add_item_to_tree(rr_tree, offset, 2,
592                             "Max number of pending sessions: %u", pntohs(dptr));
593                         dptr += 2;
594                         offset += 2;
595
596                         add_item_to_tree(rr_tree, offset, 2,
597                             "Max total sessions possible: %u", pntohs(dptr));
598                         dptr += 2;
599                         offset += 2;
600                         data_len -= 2;
601
602                         if (data_len < 2) {
603                                 add_item_to_tree(rr_tree, offset,
604                                     data_len, "(incomplete entry)");
605                                 break;
606                         }
607                         add_item_to_tree(rr_tree, offset, 2,
608                             "Session data packet size: %u", pntohs(dptr));
609                         dptr += 2;
610                         offset += 2;
611                         data_len -= 2;
612                 }
613         out:
614                 break;
615
616         default:
617                 trr = add_item_to_tree(nbns_tree, offset,
618                     (dptr - data_start) + data_len,
619                     "%s: type %s, class %s",
620                     name, type_name, class_name);
621                 rr_tree = add_rr_to_tree(trr, ETT_NBNS_RR, offset, name,
622                     name_len, type_name, class_name, ttl, data_len);
623                 offset += (dptr - data_start);
624                 add_item_to_tree(rr_tree, offset, data_len, "Data");
625                 break;
626         }
627         dptr += data_len;
628         
629         return dptr - data_start;
630 }
631
632 static int
633 dissect_query_records(const u_char *nbns_data_ptr, int count, const u_char *pd, 
634     int cur_off, GtkWidget *nbns_tree)
635 {
636         int start_off;
637         GtkWidget *qatree, *ti;
638         
639         qatree = gtk_tree_new();
640         start_off = cur_off;
641         
642         while (count-- > 0)
643                 cur_off += dissect_nbns_query(nbns_data_ptr, pd, cur_off, qatree);
644         ti = add_item_to_tree(GTK_WIDGET(nbns_tree), 
645                         start_off, cur_off - start_off, "Queries");
646         add_subtree(ti, qatree, ETT_NBNS_QRY);
647
648         return cur_off - start_off;
649 }
650
651
652
653 static int
654 dissect_answer_records(const u_char *nbns_data_ptr, int count,
655     const u_char *pd, int cur_off, GtkWidget *nbns_tree, int opcode, char *name)
656 {
657         int start_off;
658         GtkWidget *qatree, *ti;
659         
660         qatree = gtk_tree_new();
661         start_off = cur_off;
662
663         while (count-- > 0)
664                 cur_off += dissect_nbns_answer(nbns_data_ptr, pd, cur_off,
665                                         qatree, opcode);
666         ti = add_item_to_tree(GTK_WIDGET(nbns_tree), start_off, cur_off - start_off, name);
667         add_subtree(ti, qatree, ETT_NBNS_ANS);
668
669         return cur_off - start_off;
670 }
671
672 void
673 dissect_nbns(const u_char *pd, int offset, frame_data *fd, GtkTree *tree)
674 {
675         GtkWidget               *nbns_tree, *ti;
676         struct nbns_header      header;
677         int                     nm_flags;
678         const u_char            *nbns_data_ptr;
679         int                     cur_off;
680
681         char *opcode[] = {
682                 "Query",
683                 "Unknown operation (1)",
684                 "Unknown operation (2)",
685                 "Unknown operation (3)",
686                 "Unknown operation (4)",
687                 "Registration",
688                 "Release",
689                 "Wait and Acknowledge",
690                 "Refresh",
691                 "Refresh(altcode)",
692                 "Unknown operation (10)",
693                 "Unknown operation (11)",
694                 "Unknown operation (12)",
695                 "Unknown operation (13)",
696                 "Unknown operation (14)",
697                 "Multi-Homed Registration",
698         };
699
700         nbns_data_ptr = &pd[offset];
701
702         /* This is taken from samba/source/nmlib.c, parse_nmb() */
703         header.name_tran_id = pntohs(&pd[offset]);
704         header.opcode = (pd[offset+2] >> 3) & 0xf;
705         header.r = (pd[offset+2] >> 7) & 1;
706
707         nm_flags = ((pd[offset+2] & 0x7) << 4) + (pd[offset+3] >> 4);
708         header.nm_flags.bcast = (nm_flags & 1) ? 1 : 0;
709         header.nm_flags.recursion_available = (nm_flags & 8) ? 1 : 0;
710         header.nm_flags.recursion_desired = (nm_flags & 0x10) ? 1 : 0;
711         header.nm_flags.trunc = (nm_flags & 0x20) ? 1 : 0;
712         header.nm_flags.authoritative = (nm_flags & 0x40) ? 1 : 0;
713
714         header.rcode = pd[offset+3] & 0xf;
715         header.qdcount = pntohs(&pd[offset+4]);
716         header.ancount = pntohs(&pd[offset+6]);
717         header.nscount = pntohs(&pd[offset+8]);
718         header.arcount = pntohs(&pd[offset+10]);
719
720         if (check_col(fd, COL_PROTOCOL))
721                 col_add_str(fd, COL_PROTOCOL, "NBNS (UDP)");
722         if (check_col(fd, COL_INFO)) {
723                 if (header.opcode <= 15) {
724                         col_add_fstr(fd, COL_INFO, "%s %s",
725                             opcode[header.opcode], header.r ? "reply" : "request");
726                 } else {
727                         col_add_fstr(fd, COL_INFO, "Unknown operation (%d) %s",
728                             header.opcode, header.r ? "reply" : "request");
729                 }
730         }
731
732         if (tree) {
733                 ti = add_item_to_tree(GTK_WIDGET(tree), offset, END_OF_FRAME,
734                                 "NetBIOS Name Service");
735                 nbns_tree = gtk_tree_new();
736                 add_subtree(ti, nbns_tree, ETT_NBNS);
737
738                 add_item_to_tree(nbns_tree, offset,      2, "Transaction ID: 0x%04X",
739                                 header.name_tran_id);
740                 add_item_to_tree(nbns_tree, offset +  2, 1, "Type: %s",
741                                 header.r == 0 ? "Request" : "Response" );
742                 
743                 if (header.opcode <= 15) {
744                         add_item_to_tree(nbns_tree, offset + 2, 1, "Operation: %s (%d)",
745                                         opcode[header.opcode], header.opcode);
746                 }
747                 else {
748                         add_item_to_tree(nbns_tree, offset + 2, 1, "Operation: Unknown (%d)",
749                                         header.opcode);
750                 }
751                 add_item_to_tree(nbns_tree, offset +  4, 2, "Questions: %d",
752                                         header.qdcount);
753                 add_item_to_tree(nbns_tree, offset +  6, 2, "Answer RRs: %d",
754                                         header.ancount);
755                 add_item_to_tree(nbns_tree, offset +  8, 2, "Authority RRs: %d",
756                                         header.nscount);
757                 add_item_to_tree(nbns_tree, offset + 10, 2, "Additional RRs: %d",
758                                         header.arcount);
759
760                 cur_off = offset + 12;
761     
762                 if (header.qdcount > 0)
763                         cur_off += dissect_query_records(nbns_data_ptr,
764                                         header.qdcount, pd, cur_off, nbns_tree);
765
766                 if (header.ancount > 0)
767                         cur_off += dissect_answer_records(nbns_data_ptr,
768                                         header.ancount, pd, cur_off, nbns_tree,
769                                         header.opcode, "Answers");
770
771                 if (header.nscount > 0)
772                         cur_off += dissect_answer_records(nbns_data_ptr,
773                                         header.nscount, pd, cur_off, nbns_tree, 
774                                         header.opcode,
775                                         "Authoritative nameservers");
776
777                 if (header.arcount > 0)
778                         cur_off += dissect_answer_records(nbns_data_ptr,
779                                         header.arcount, pd, cur_off, nbns_tree, 
780                                         header.opcode, "Additional records");
781         }
782 }
783
784
785 void
786 dissect_nbdgm(const u_char *pd, int offset, frame_data *fd, GtkTree *tree)
787 {
788         GtkWidget               *nbdgm_tree, *ti;
789         struct nbdgm_header     header;
790         int                     flags;
791         int                     message_index;
792
793         char *message[] = {
794                 "Unknown",
795                 "Direct_unique datagram",
796                 "Direct_group datagram",
797                 "Broadcast datagram",
798                 "Datagram error",
799                 "Datagram query request",
800                 "Datagram positive query response",
801                 "Datagram negative query response"
802         };
803
804         char *node[] = {
805                 "B node",
806                 "P node",
807                 "M node",
808                 "NBDD"
809         };
810
811         static value_string error_codes[] = {
812                 { 0x82, "Destination name not present" },
813                 { 0x83, "Invalid source name format" },
814                 { 0x84, "Invalid destination name format" },
815                 { 0x00, NULL }
816         };
817
818         char *yesno[] = { "No", "Yes" };
819
820         char name[32];
821         int len, name_len, type, class;
822
823         header.msg_type = pd[offset];
824         
825         flags = pd[offset+1];
826         header.flags.more = flags & 1;
827         header.flags.first = (flags & 2) >> 1;
828         header.flags.node_type = (flags & 12) >> 2;
829
830         header.dgm_id = pntohs(&pd[offset+2]);
831         memcpy(&header.src_ip, &pd[offset+4], 4);
832         header.src_port = pntohs(&pd[offset+8]);
833
834         if (header.msg_type == 0x10 ||
835                         header.msg_type == 0x11 || header.msg_type == 0x12) {
836                 header.dgm_length = pntohs(&pd[offset+10]);
837                 header.pkt_offset = pntohs(&pd[offset+12]);
838         }
839         else if (header.msg_type == 0x13) {
840                 header.error_code = pntohs(&pd[offset+10]);
841         }
842
843         message_index = header.msg_type - 0x0f;
844         if (message_index < 1 || message_index > 8) {
845                 message_index = 0;
846         }
847
848         if (check_col(fd, COL_PROTOCOL))
849                 col_add_str(fd, COL_PROTOCOL, "NetBIOS");
850         if (check_col(fd, COL_INFO)) {
851                 col_add_fstr(fd, COL_INFO, "%s", message[message_index]);
852         }
853
854         if (tree) {
855                 ti = add_item_to_tree(GTK_WIDGET(tree), offset, header.dgm_length,
856                                 "NetBIOS Datagram");
857                 nbdgm_tree = gtk_tree_new();
858                 add_subtree(ti, nbdgm_tree, ETT_NBDGM);
859
860                 add_item_to_tree(nbdgm_tree, offset, 1, "Message Type: %s",
861                                 message[message_index]);
862                 add_item_to_tree(nbdgm_tree, offset+1, 1, "More fragments follow: %s",
863                                 yesno[header.flags.more]);
864                 add_item_to_tree(nbdgm_tree, offset+1, 1, "This is first fragment: %s",
865                                 yesno[header.flags.first]);
866                 add_item_to_tree(nbdgm_tree, offset+1, 1, "Node Type: %s",
867                                 node[header.flags.node_type]);
868
869                 add_item_to_tree(nbdgm_tree, offset+2, 2, "Datagram ID: 0x%04X",
870                                 header.dgm_id);
871                 add_item_to_tree(nbdgm_tree, offset+4, 4, "Source IP: %s",
872                                 ip_to_str((guint8 *)&header.src_ip));
873                 add_item_to_tree(nbdgm_tree, offset+8, 2, "Source Port: %d",
874                                 header.src_port);
875
876                 offset += 10;
877
878                 if (header.msg_type == 0x10 ||
879                                 header.msg_type == 0x11 || header.msg_type == 0x12) {
880
881                         add_item_to_tree(nbdgm_tree, offset, 2,
882                                         "Datagram length: %d bytes", header.dgm_length);
883                         add_item_to_tree(nbdgm_tree, offset+2, 2,
884                                         "Packet offset: %d bytes", header.pkt_offset);
885
886                         offset += 4;
887
888                         /* Source name */
889                         len = get_nbns_name_type_class(&pd[offset], pd, offset, name,
890                                 &name_len, &type, &class);
891
892                         len -= 4;
893                         add_item_to_tree(nbdgm_tree, offset, len, "Source name: %s",
894                                         name);
895                         offset += len;
896
897                         /* Destination name */
898                         len = get_nbns_name_type_class(&pd[offset], pd, offset, name,
899                                 &name_len, &type, &class);
900
901                         len -= 4;
902                         add_item_to_tree(nbdgm_tree, offset, len, "Destination name: %s",
903                                         name);
904                         offset += len;
905
906                         /* here we can pass the packet off to the next protocol */
907                 }
908                 else if (header.msg_type == 0x13) {
909                         add_item_to_tree(nbdgm_tree, offset, 1, "Error code: %s",
910                                 match_strval(header.error_code, error_codes));
911                 }
912                 else {
913                         /* Destination name */
914                         len = get_nbns_name_type_class(&pd[offset], pd, offset, name,
915                                 &name_len, &type, &class);
916
917                         len -= 4;
918                         add_item_to_tree(nbdgm_tree, offset, len, "Destination name: %s",
919                                         name);
920                 }
921
922         }
923 }