Decode the word containing the opcode, flags, reply code, etc. in DNS
[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.11 1999/01/04 09:13:46 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
120 static char *
121 nbns_type_name (int type)
122 {
123         switch (type) {
124         case T_NB:
125                 return "NB";
126         case T_NBSTAT:
127                 return "NBSTAT";
128         }
129         
130         return "unknown";
131 }
132
133 /* "Canonicalize" a 16-character NetBIOS name by:
134  *
135  *      removing and saving the last byte;
136  *
137  *      stripping trailing blanks;
138  *
139  *      appending the trailing byte, as a hex number, in square brackets. */
140 static char *
141 canonicalize_netbios_name(char *nbname)
142 {
143         char *pnbname;
144         u_char lastchar;
145
146         /* Get the last character of the name, as it's a special number
147          * indicating the type of the name, rather than part of the name
148          * *per se*. */
149         pnbname = nbname + 15;  /* point to the 16th character */
150         lastchar = *(unsigned char *)pnbname;
151
152         /* Now strip off any trailing blanks used to pad it to
153          * 16 bytes. */
154         while (pnbname > &nbname[0]) {
155                 if (*(pnbname - 1) != ' ')
156                         break;          /* found non-blank character */
157                 pnbname--;              /* blank - skip over it */
158         }
159
160         /* Replace the last character with its hex value, in square
161          * brackets, to make it easier to tell what it is. */
162         sprintf(pnbname, "[%02X]", lastchar);
163         pnbname += 4;
164         return pnbname;
165 }
166
167 static int
168 get_nbns_name(const u_char *nbns_data_ptr, const u_char *pd,
169     int offset, char *name_ret)
170 {
171         int name_len;
172         char name[MAXDNAME];
173         char nbname[MAXDNAME+4];        /* 4 for [<last char>] */
174         char *pname, *pnbname, cname, cnbname;
175
176         name_len = get_dns_name(nbns_data_ptr, pd, offset, name, sizeof(name));
177         
178         /* OK, now undo the first-level encoding. */
179         pname = &name[0];
180         pnbname = &nbname[0];
181         for (;;) {
182                 /* Every two characters of the first level-encoded name
183                  * turn into one character in the decoded name. */
184                 cname = *pname;
185                 if (cname == '\0')
186                         break;          /* no more characters */
187                 if (cname == '.')
188                         break;          /* scope ID follows */
189                 if (cname < 'A' || cname > 'Z') {
190                         /* Not legal. */
191                         strcpy(nbname,
192                             "Illegal NetBIOS name (character not between A and Z in first-level encoding)");
193                         goto bad;
194                 }
195                 cname -= 'A';
196                 cnbname = cname << 4;
197                 pname++;
198
199                 cname = *pname;
200                 if (cname == '\0' || cname == '.') {
201                         /* No more characters in the name - but we're in
202                          * the middle of a pair.  Not legal. */
203                         strcpy(nbname,
204                             "Illegal NetBIOS name (odd number of bytes)");
205                         goto bad;
206                 }
207                 if (cname < 'A' || cname > 'Z') {
208                         /* Not legal. */
209                         strcpy(nbname,
210                             "Illegal NetBIOS name (character not between A and Z in first-level encoding)");
211                         goto bad;
212                 }
213                 cname -= 'A';
214                 cnbname |= cname;
215                 pname++;
216
217                 /* Store the character. */
218                 *pnbname++ = cnbname;
219         }
220
221         /* NetBIOS names are supposed to be exactly 16 bytes long. */
222         if (pnbname - nbname == 16) {
223                 /* This one is; canonicalize its name. */
224                 pnbname = canonicalize_netbios_name(nbname);
225         } else {
226                 sprintf(nbname, "Illegal NetBIOS name (%ld bytes long)",
227                     (long)(pnbname - nbname));
228                 goto bad;
229         }
230         if (cname == '.') {
231                 /* We have a scope ID, starting at "pname"; append that to
232                  * the decoded host name. */
233                 strcpy(pnbname, pname);
234         } else {
235                 /* Terminate the decoded host name. */
236                 *pnbname = '\0';
237         }
238
239 bad:
240         strcpy (name_ret, nbname);
241         return name_len;
242 }
243
244
245 static int
246 get_nbns_name_type_class(const u_char *nbns_data_ptr, const u_char *pd,
247     int offset, char *name_ret, int *name_len_ret, int *type_ret,
248     int *class_ret)
249 {
250         int name_len;
251         int type;
252         int class;
253
254         name_len = get_nbns_name(nbns_data_ptr, pd, offset, name_ret);
255         offset += name_len;
256         
257         type = pntohs(&pd[offset]);
258         offset += 2;
259         class = pntohs(&pd[offset]);
260
261         *type_ret = type;
262         *class_ret = class;
263         *name_len_ret = name_len;
264
265         return name_len + 4;
266 }
267
268
269 static int
270 dissect_nbns_query(const u_char *nbns_data_ptr, const u_char *pd, int offset,
271     GtkWidget *nbns_tree)
272 {
273         int len;
274         char name[MAXDNAME];
275         int name_len;
276         int type;
277         int class;
278         char *class_name;
279         char *type_name;
280         const u_char *dptr;
281         const u_char *data_start;
282         GtkWidget *q_tree, *tq;
283
284         data_start = dptr = pd + offset;
285
286         len = get_nbns_name_type_class(nbns_data_ptr, pd, offset, name,
287             &name_len, &type, &class);
288         dptr += len;
289
290         type_name = nbns_type_name(type);
291         class_name = dns_class_name(class);
292
293         tq = add_item_to_tree(nbns_tree, offset, len, "%s: type %s, class %s", 
294             name, type_name, class_name);
295         q_tree = gtk_tree_new();
296         add_subtree(tq, q_tree, ETT_NBNS_QD);
297
298         add_item_to_tree(q_tree, offset, name_len, "Name: %s", name);
299         offset += name_len;
300
301         add_item_to_tree(q_tree, offset, 2, "Type: %s", type_name);
302         offset += 2;
303
304         add_item_to_tree(q_tree, offset, 2, "Class: %s", class_name);
305         offset += 2;
306         
307         return dptr - data_start;
308 }
309
310
311 static int
312 dissect_nbns_answer(const u_char *nbns_data_ptr, const u_char *pd, int offset,
313     GtkWidget *nbns_tree, int opcode)
314 {
315         int len;
316         char name[MAXDNAME];
317         int name_len;
318         int type;
319         int class;
320         char *class_name;
321         char *type_name;
322         const u_char *dptr;
323         const u_char *data_start;
324         u_int ttl;
325         u_short data_len;
326         u_short flags;
327         GtkWidget *rr_tree, *trr;
328
329         data_start = dptr = pd + offset;
330
331         len = get_nbns_name_type_class(nbns_data_ptr, pd, offset, name,
332             &name_len, &type, &class);
333         dptr += len;
334
335         type_name = nbns_type_name(type);
336         class_name = dns_class_name(class);
337
338         ttl = pntohl(dptr);
339         dptr += 4;
340
341         data_len = pntohs(dptr);
342         dptr += 2;
343
344         switch (type) {
345         case T_NB:              /* "NB" record */
346                 trr = add_item_to_tree(nbns_tree, offset,
347                     (dptr - data_start) + data_len,
348                     "%s: type %s, class %s",
349                     name, type_name, class_name);
350                 rr_tree = add_rr_to_tree(trr, ETT_NBNS_RR, offset, name,
351                     name_len, type_name, class_name, ttl, data_len);
352                 offset += (dptr - data_start);
353                 while (data_len > 0) {
354                         if (opcode == OPCODE_WACK) {
355                                 /* WACK response.  This doesn't contain the
356                                  * same type of RR data as other T_NB
357                                  * responses.  */
358                                 if (data_len < 2) {
359                                         add_item_to_tree(rr_tree, offset,
360                                             data_len, "(incomplete entry)");
361                                         break;
362                                 }
363                                 flags = pntohs(dptr);
364                                 dptr += 2;
365                                 add_item_to_tree(rr_tree, offset, 2,
366                                     "Flags: 0x%x", flags);
367                                 offset += 2;
368                                 data_len -= 2;
369                         } else {
370                                 if (data_len < 2) {
371                                         add_item_to_tree(rr_tree, offset,
372                                             data_len, "(incomplete entry)");
373                                         break;
374                                 }
375                                 flags = pntohs(dptr);
376                                 dptr += 2;
377                                 add_item_to_tree(rr_tree, offset, 2,
378                                     "Flags: 0x%x", flags);
379                                 offset += 2;
380                                 data_len -= 2;
381
382                                 if (data_len < 4) {
383                                         add_item_to_tree(rr_tree, offset,
384                                             data_len, "(incomplete entry)");
385                                         break;
386                                 }
387                                 add_item_to_tree(rr_tree, offset, 4,
388                                     "Addr: %s",
389                                     ip_to_str((guint8 *)dptr));
390                                 dptr += 4;
391                                 offset += 4;
392                                 data_len -= 4;
393                         }
394                 }
395                 break;
396
397         case T_NBSTAT:  /* "NBSTAT" record */
398                 {
399                         u_int num_names;
400                         char nbname[16+4+1];    /* 4 for [<last char>] */
401                         u_short name_flags;
402                         
403                         trr = add_item_to_tree(nbns_tree, offset,
404                             (dptr - data_start) + data_len,
405                             "%s: type %s, class %s",
406                             name, type_name, class_name);
407                         rr_tree = add_rr_to_tree(trr, ETT_NBNS_RR, offset, name,
408                             name_len, type_name, class_name, ttl, data_len);
409                         offset += (dptr - data_start);
410                         if (data_len < 1) {
411                                 add_item_to_tree(rr_tree, offset,
412                                     data_len, "(incomplete entry)");
413                                 break;
414                         }
415                         num_names = *dptr;
416                         dptr += 1;
417                         add_item_to_tree(rr_tree, offset, 2,
418                             "Number of names: %u", num_names);
419                         offset += 1;
420
421                         while (num_names != 0) {
422                                 if (data_len < 16) {
423                                         add_item_to_tree(rr_tree, offset,
424                                             data_len, "(incomplete entry)");
425                                         goto out;
426                                 }
427                                 memcpy(nbname, dptr, 16);
428                                 dptr += 16;
429                                 canonicalize_netbios_name(nbname);
430                                 add_item_to_tree(rr_tree, offset, 16,
431                                     "Name: %s", nbname);
432                                 offset += 16;
433                                 data_len -= 16;
434
435                                 if (data_len < 2) {
436                                         add_item_to_tree(rr_tree, offset,
437                                             data_len, "(incomplete entry)");
438                                         goto out;
439                                 }
440                                 name_flags = pntohs(dptr);
441                                 dptr += 2;
442                                 add_item_to_tree(rr_tree, offset, 2,
443                                     "Name flags: 0x%x", name_flags);
444                                 offset += 2;
445                                 data_len -= 2;
446
447                                 num_names--;
448                         }
449
450                         if (data_len < 6) {
451                                 add_item_to_tree(rr_tree, offset,
452                                     data_len, "(incomplete entry)");
453                                 break;
454                         }
455                         add_item_to_tree(rr_tree, offset, 6,
456                             "Unit ID: %s",
457                             ether_to_str((guint8 *)dptr));
458                         dptr += 6;
459                         offset += 6;
460                         data_len -= 6;
461
462                         if (data_len < 1) {
463                                 add_item_to_tree(rr_tree, offset,
464                                     data_len, "(incomplete entry)");
465                                 break;
466                         }
467                         add_item_to_tree(rr_tree, offset, 1,
468                             "Jumpers: 0x%x", *dptr);
469                         dptr += 1;
470                         offset += 1;
471                         data_len -= 1;
472
473                         if (data_len < 1) {
474                                 add_item_to_tree(rr_tree, offset,
475                                     data_len, "(incomplete entry)");
476                                 break;
477                         }
478                         add_item_to_tree(rr_tree, offset, 1,
479                             "Test result: 0x%x", *dptr);
480                         dptr += 1;
481                         offset += 1;
482                         data_len -= 1;
483
484                         if (data_len < 2) {
485                                 add_item_to_tree(rr_tree, offset,
486                                     data_len, "(incomplete entry)");
487                                 break;
488                         }
489                         add_item_to_tree(rr_tree, offset, 2,
490                             "Version number: 0x%x", pntohs(dptr));
491                         dptr += 2;
492                         offset += 2;
493                         data_len -= 2;
494
495                         if (data_len < 2) {
496                                 add_item_to_tree(rr_tree, offset,
497                                     data_len, "(incomplete entry)");
498                                 break;
499                         }
500                         add_item_to_tree(rr_tree, offset, 2,
501                             "Period of statistics: 0x%x", pntohs(dptr));
502                         dptr += 2;
503                         offset += 2;
504                         data_len -= 2;
505
506                         if (data_len < 2) {
507                                 add_item_to_tree(rr_tree, offset,
508                                     data_len, "(incomplete entry)");
509                                 break;
510                         }
511                         add_item_to_tree(rr_tree, offset, 2,
512                             "Number of CRCs: %u", pntohs(dptr));
513                         dptr += 2;
514                         offset += 2;
515                         data_len -= 2;
516
517                         if (data_len < 2) {
518                                 add_item_to_tree(rr_tree, offset,
519                                     data_len, "(incomplete entry)");
520                                 break;
521                         }
522                         add_item_to_tree(rr_tree, offset, 2,
523                             "Number of alignment errors: %u", pntohs(dptr));
524                         dptr += 2;
525                         offset += 2;
526                         data_len -= 2;
527
528                         if (data_len < 2) {
529                                 add_item_to_tree(rr_tree, offset,
530                                     data_len, "(incomplete entry)");
531                                 break;
532                         }
533                         add_item_to_tree(rr_tree, offset, 2,
534                             "Number of collisions: %u", pntohs(dptr));
535                         dptr += 2;
536                         offset += 2;
537                         data_len -= 2;
538
539                         if (data_len < 2) {
540                                 add_item_to_tree(rr_tree, offset,
541                                     data_len, "(incomplete entry)");
542                                 break;
543                         }
544                         add_item_to_tree(rr_tree, offset, 2,
545                             "Number of send aborts: %u", pntohs(dptr));
546                         dptr += 2;
547                         offset += 2;
548                         data_len -= 2;
549
550                         if (data_len < 4) {
551                                 add_item_to_tree(rr_tree, offset,
552                                     data_len, "(incomplete entry)");
553                                 break;
554                         }
555                         add_item_to_tree(rr_tree, offset, 4,
556                             "Number of good sends: %u", pntohl(dptr));
557                         dptr += 4;
558                         offset += 4;
559                         data_len -= 4;
560
561                         if (data_len < 4) {
562                                 add_item_to_tree(rr_tree, offset,
563                                     data_len, "(incomplete entry)");
564                                 break;
565                         }
566                         add_item_to_tree(rr_tree, offset, 4,
567                             "Number of good receives: %u", pntohl(dptr));
568                         dptr += 4;
569                         offset += 4;
570                         data_len -= 4;
571
572                         if (data_len < 2) {
573                                 add_item_to_tree(rr_tree, offset,
574                                     data_len, "(incomplete entry)");
575                                 break;
576                         }
577                         add_item_to_tree(rr_tree, offset, 2,
578                             "Number of retransmits: %u", pntohs(dptr));
579                         dptr += 2;
580                         offset += 2;
581                         data_len -= 2;
582
583                         if (data_len < 2) {
584                                 add_item_to_tree(rr_tree, offset,
585                                     data_len, "(incomplete entry)");
586                                 break;
587                         }
588                         add_item_to_tree(rr_tree, offset, 2,
589                             "Number of no resource conditions: %u", pntohs(dptr));
590                         dptr += 2;
591                         offset += 2;
592                         data_len -= 2;
593
594                         if (data_len < 2) {
595                                 add_item_to_tree(rr_tree, offset,
596                                     data_len, "(incomplete entry)");
597                                 break;
598                         }
599                         add_item_to_tree(rr_tree, offset, 2,
600                             "Number of command blocks: %u", pntohs(dptr));
601                         dptr += 2;
602                         offset += 2;
603                         data_len -= 2;
604
605                         if (data_len < 2) {
606                                 add_item_to_tree(rr_tree, offset,
607                                     data_len, "(incomplete entry)");
608                                 break;
609                         }
610                         add_item_to_tree(rr_tree, offset, 2,
611                             "Number of pending sessions: %u", pntohs(dptr));
612                         dptr += 2;
613                         offset += 2;
614                         data_len -= 2;
615
616                         if (data_len < 2) {
617                                 add_item_to_tree(rr_tree, offset,
618                                     data_len, "(incomplete entry)");
619                                 break;
620                         }
621                         add_item_to_tree(rr_tree, offset, 2,
622                             "Max number of pending sessions: %u", pntohs(dptr));
623                         dptr += 2;
624                         offset += 2;
625
626                         add_item_to_tree(rr_tree, offset, 2,
627                             "Max total sessions possible: %u", pntohs(dptr));
628                         dptr += 2;
629                         offset += 2;
630                         data_len -= 2;
631
632                         if (data_len < 2) {
633                                 add_item_to_tree(rr_tree, offset,
634                                     data_len, "(incomplete entry)");
635                                 break;
636                         }
637                         add_item_to_tree(rr_tree, offset, 2,
638                             "Session data packet size: %u", pntohs(dptr));
639                         dptr += 2;
640                         offset += 2;
641                         data_len -= 2;
642                 }
643         out:
644                 break;
645
646         default:
647                 trr = add_item_to_tree(nbns_tree, offset,
648                     (dptr - data_start) + data_len,
649                     "%s: type %s, class %s",
650                     name, type_name, class_name);
651                 rr_tree = add_rr_to_tree(trr, ETT_NBNS_RR, offset, name,
652                     name_len, type_name, class_name, ttl, data_len);
653                 offset += (dptr - data_start);
654                 add_item_to_tree(rr_tree, offset, data_len, "Data");
655                 break;
656         }
657         dptr += data_len;
658         
659         return dptr - data_start;
660 }
661
662 static int
663 dissect_query_records(const u_char *nbns_data_ptr, int count, const u_char *pd, 
664     int cur_off, GtkWidget *nbns_tree)
665 {
666         int start_off;
667         GtkWidget *qatree, *ti;
668         
669         start_off = cur_off;
670         ti = add_item_to_tree(GTK_WIDGET(nbns_tree), 
671                         start_off, 0, "Queries");
672         qatree = gtk_tree_new();
673         add_subtree(ti, qatree, ETT_NBNS_QRY);
674         while (count-- > 0)
675                 cur_off += dissect_nbns_query(nbns_data_ptr, pd, cur_off, qatree);
676         set_item_len(ti, cur_off - start_off);
677
678         return cur_off - start_off;
679 }
680
681
682
683 static int
684 dissect_answer_records(const u_char *nbns_data_ptr, int count,
685     const u_char *pd, int cur_off, GtkWidget *nbns_tree, int opcode, char *name)
686 {
687         int start_off;
688         GtkWidget *qatree, *ti;
689         
690         start_off = cur_off;
691         ti = add_item_to_tree(GTK_WIDGET(nbns_tree),
692                         start_off, 0, name);
693         qatree = gtk_tree_new();
694         add_subtree(ti, qatree, ETT_NBNS_ANS);
695         while (count-- > 0)
696                 cur_off += dissect_nbns_answer(nbns_data_ptr, pd, cur_off,
697                                         qatree, opcode);
698         set_item_len(ti, cur_off - start_off);
699         return cur_off - start_off;
700 }
701
702 void
703 dissect_nbns(const u_char *pd, int offset, frame_data *fd, GtkTree *tree)
704 {
705         const u_char            *nbns_data_ptr;
706         GtkWidget               *nbns_tree, *ti, *field_tree, *tf;
707         guint16                 id, flags, quest, ans, auth, add;
708         char                    buf[128+1];
709         int                     cur_off;
710         static const value_string opcode_vals[] = {
711                   { OPCODE_QUERY,          "Name query"                 },
712                   { OPCODE_REGISTRATION,   "Registration"               },
713                   { OPCODE_RELEASE,        "Release"                    },
714                   { OPCODE_WACK,           "Wait for acknowledgment"    },
715                   { OPCODE_REFRESH,        "Refresh"                    },
716                   { OPCODE_REFRESHALT,     "Refresh (alternate opcode)" },
717                   { OPCODE_MHREGISTRATION, "Multi-homed registration"   },
718                   { 0,                     NULL                         }
719         };
720         static const value_string rcode_vals[] = {
721                   { RCODE_NOERROR,   "No error"              },
722                   { RCODE_FMTERROR,  "Format error"          },
723                   { RCODE_SERVFAIL,  "Server failure"        },
724                   { RCODE_NAMEERROR, "Name error"            },
725                   { RCODE_NOTIMPL,   "Not implemented"       },
726                   { RCODE_REFUSED,   "Refused"               },
727                   { RCODE_ACTIVE,    "Name is active"        },
728                   { RCODE_CONFLICT,  "Name is in conflict"   },
729                   { 0,               NULL                    }
730         };
731
732         nbns_data_ptr = &pd[offset];
733
734         /* To do: check for runts, errs, etc. */
735         id    = pntohs(&pd[offset + NBNS_ID]);
736         flags = pntohs(&pd[offset + NBNS_FLAGS]);
737         quest = pntohs(&pd[offset + NBNS_QUEST]);
738         ans   = pntohs(&pd[offset + NBNS_ANS]);
739         auth  = pntohs(&pd[offset + NBNS_AUTH]);
740         add   = pntohs(&pd[offset + NBNS_ADD]);
741
742         if (check_col(fd, COL_PROTOCOL))
743                 col_add_str(fd, COL_PROTOCOL, "NBNS (UDP)");
744         if (check_col(fd, COL_INFO)) {
745                 col_add_fstr(fd, COL_INFO, "%s%s",
746                     val_to_str(flags & F_OPCODE, opcode_vals,
747                       "Unknown operation (%x)"),
748                     (flags & F_RESPONSE) ? " response" : "");
749         }
750
751         if (tree) {
752                 ti = add_item_to_tree(GTK_WIDGET(tree), offset, END_OF_FRAME,
753                                 "NetBIOS Name Service");
754                 nbns_tree = gtk_tree_new();
755                 add_subtree(ti, nbns_tree, ETT_NBNS);
756
757                 add_item_to_tree(nbns_tree, offset + NBNS_ID, 2,
758                                 "Transaction ID: 0x%04X", id);
759
760                 strcpy(buf, val_to_str(flags & F_OPCODE, opcode_vals,
761                                 "Unknown (%x)"));
762                 if (flags & F_RESPONSE) {
763                         strcat(buf, " response");
764                         strcat(buf, ", ");
765                         strcat(buf, val_to_str(flags & F_RCODE, rcode_vals,
766                             "Unknown error (%x)"));
767                 }
768                 tf = add_item_to_tree(nbns_tree, offset + NBNS_FLAGS, 2,
769                                 "Flags: 0x%04x (%s)", flags, buf);
770                 field_tree = gtk_tree_new();
771                 add_subtree(tf, field_tree, ETT_NBNS_FLAGS);
772                 add_item_to_tree(field_tree, offset + NBNS_FLAGS, 2, "%s",
773                     decode_boolean_bitfield(flags, F_RESPONSE,
774                       2*8, "Response", "Query"));
775                 add_item_to_tree(field_tree, offset + NBNS_FLAGS, 2, "%s",
776                     decode_enumerated_bitfield(flags, F_OPCODE,
777                       2*8, opcode_vals, "%s"));
778                 if (flags & F_RESPONSE) {
779                         add_item_to_tree(field_tree, offset + NBNS_FLAGS, 2,
780                                 "%s",
781                                 decode_boolean_bitfield(flags, F_AUTHORITATIVE,
782                                         2*8,
783                                         "Server is an authority for domain",
784                                         "Server isn't an authority for domain"));
785                 }
786                 add_item_to_tree(field_tree, offset + NBNS_FLAGS, 2, "%s",
787                                 decode_boolean_bitfield(flags, F_TRUNCATED,
788                                         2*8,
789                                         "Message is truncated",
790                                         "Message is not truncated"));
791                 add_item_to_tree(field_tree, offset + NBNS_FLAGS, 2, "%s",
792                                 decode_boolean_bitfield(flags, F_RECDESIRED,
793                                         2*8,
794                                         "Do query recursively",
795                                         "Don't do query recursively"));
796                 if (flags & F_RESPONSE) {
797                         add_item_to_tree(field_tree, offset + NBNS_FLAGS, 2,
798                                 "%s",
799                                 decode_boolean_bitfield(flags, F_RECAVAIL,
800                                         2*8,
801                                         "Server can do recursive queries",
802                                         "Server can't do recursive queries"));
803                 }
804                 add_item_to_tree(field_tree, offset + NBNS_FLAGS, 2, "%s",
805                                 decode_boolean_bitfield(flags, F_BROADCAST,
806                                         2*8,
807                                         "Broadcast packet",
808                                         "Not a broadcast packet"));
809                 if (flags & F_RESPONSE) {
810                         add_item_to_tree(field_tree, offset + NBNS_FLAGS, 2,
811                                 "%s",
812                                 decode_enumerated_bitfield(flags, F_RCODE,
813                                         2*8,
814                                         rcode_vals, "%s"));
815                 }
816                 add_item_to_tree(nbns_tree, offset + NBNS_QUEST, 2,
817                                         "Questions: %d",
818                                         quest);
819                 add_item_to_tree(nbns_tree, offset + NBNS_ANS, 2,
820                                         "Answer RRs: %d",
821                                         ans);
822                 add_item_to_tree(nbns_tree, offset + NBNS_AUTH, 2,
823                                         "Authority RRs: %d",
824                                         auth);
825                 add_item_to_tree(nbns_tree, offset + NBNS_ADD, 2,
826                                         "Additional RRs: %d",
827                                         add);
828
829                 cur_off = offset + NBNS_HDRLEN;
830     
831                 if (quest > 0)
832                         cur_off += dissect_query_records(nbns_data_ptr,
833                                         quest, pd, cur_off, nbns_tree);
834
835                 if (ans > 0)
836                         cur_off += dissect_answer_records(nbns_data_ptr,
837                                         ans, pd, cur_off, nbns_tree,
838                                         flags & F_OPCODE,
839                                         "Answers");
840
841                 if (auth > 0)
842                         cur_off += dissect_answer_records(nbns_data_ptr,
843                                         auth, pd, cur_off, nbns_tree, 
844                                         flags & F_OPCODE,
845                                         "Authoritative nameservers");
846
847                 if (add > 0)
848                         cur_off += dissect_answer_records(nbns_data_ptr,
849                                         add, pd, cur_off, nbns_tree, 
850                                         flags & F_OPCODE,
851                                         "Additional records");
852         }
853 }
854
855
856 void
857 dissect_nbdgm(const u_char *pd, int offset, frame_data *fd, GtkTree *tree)
858 {
859         GtkWidget               *nbdgm_tree, *ti;
860         struct nbdgm_header     header;
861         int                     flags;
862         int                     message_index;
863
864         char *message[] = {
865                 "Unknown",
866                 "Direct_unique datagram",
867                 "Direct_group datagram",
868                 "Broadcast datagram",
869                 "Datagram error",
870                 "Datagram query request",
871                 "Datagram positive query response",
872                 "Datagram negative query response"
873         };
874
875         char *node[] = {
876                 "B node",
877                 "P node",
878                 "M node",
879                 "NBDD"
880         };
881
882         static value_string error_codes[] = {
883                 { 0x82, "Destination name not present" },
884                 { 0x83, "Invalid source name format" },
885                 { 0x84, "Invalid destination name format" },
886                 { 0x00, NULL }
887         };
888
889         char *yesno[] = { "No", "Yes" };
890
891         char name[32];
892         int len;
893
894         header.msg_type = pd[offset];
895         
896         flags = pd[offset+1];
897         header.flags.more = flags & 1;
898         header.flags.first = (flags & 2) >> 1;
899         header.flags.node_type = (flags & 12) >> 2;
900
901         header.dgm_id = pntohs(&pd[offset+2]);
902         memcpy(&header.src_ip, &pd[offset+4], 4);
903         header.src_port = pntohs(&pd[offset+8]);
904
905         if (header.msg_type == 0x10 ||
906                         header.msg_type == 0x11 || header.msg_type == 0x12) {
907                 header.dgm_length = pntohs(&pd[offset+10]);
908                 header.pkt_offset = pntohs(&pd[offset+12]);
909         }
910         else if (header.msg_type == 0x13) {
911                 header.error_code = pntohs(&pd[offset+10]);
912         }
913
914         message_index = header.msg_type - 0x0f;
915         if (message_index < 1 || message_index > 8) {
916                 message_index = 0;
917         }
918
919         if (check_col(fd, COL_PROTOCOL))
920                 col_add_str(fd, COL_PROTOCOL, "NBDS (UDP)");
921         if (check_col(fd, COL_INFO)) {
922                 col_add_fstr(fd, COL_INFO, "%s", message[message_index]);
923         }
924
925         if (tree) {
926                 ti = add_item_to_tree(GTK_WIDGET(tree), offset, header.dgm_length,
927                                 "NetBIOS Datagram Service");
928                 nbdgm_tree = gtk_tree_new();
929                 add_subtree(ti, nbdgm_tree, ETT_NBDGM);
930
931                 add_item_to_tree(nbdgm_tree, offset, 1, "Message Type: %s",
932                                 message[message_index]);
933                 add_item_to_tree(nbdgm_tree, offset+1, 1, "More fragments follow: %s",
934                                 yesno[header.flags.more]);
935                 add_item_to_tree(nbdgm_tree, offset+1, 1, "This is first fragment: %s",
936                                 yesno[header.flags.first]);
937                 add_item_to_tree(nbdgm_tree, offset+1, 1, "Node Type: %s",
938                                 node[header.flags.node_type]);
939
940                 add_item_to_tree(nbdgm_tree, offset+2, 2, "Datagram ID: 0x%04X",
941                                 header.dgm_id);
942                 add_item_to_tree(nbdgm_tree, offset+4, 4, "Source IP: %s",
943                                 ip_to_str((guint8 *)&header.src_ip));
944                 add_item_to_tree(nbdgm_tree, offset+8, 2, "Source Port: %d",
945                                 header.src_port);
946
947                 offset += 10;
948
949                 if (header.msg_type == 0x10 ||
950                                 header.msg_type == 0x11 || header.msg_type == 0x12) {
951
952                         add_item_to_tree(nbdgm_tree, offset, 2,
953                                         "Datagram length: %d bytes", header.dgm_length);
954                         add_item_to_tree(nbdgm_tree, offset+2, 2,
955                                         "Packet offset: %d bytes", header.pkt_offset);
956
957                         offset += 4;
958
959                         /* Source name */
960                         len = get_nbns_name(&pd[offset], pd, offset, name);
961
962                         add_item_to_tree(nbdgm_tree, offset, len, "Source name: %s",
963                                         name);
964                         offset += len;
965
966                         /* Destination name */
967                         len = get_nbns_name(&pd[offset], pd, offset, name);
968
969                         add_item_to_tree(nbdgm_tree, offset, len, "Destination name: %s",
970                                         name);
971                         offset += len;
972
973                         /* here we can pass the packet off to the next protocol */
974                         dissect_data(pd, offset, fd, GTK_TREE(nbdgm_tree));
975                 }
976                 else if (header.msg_type == 0x13) {
977                         add_item_to_tree(nbdgm_tree, offset, 1, "Error code: %s",
978                                 val_to_str(header.error_code, error_codes, "Unknown (0x%x)"));
979                 }
980                 else if (header.msg_type == 0x14 ||
981                                 header.msg_type == 0x15 || header.msg_type == 0x16) {
982                         /* Destination name */
983                         len = get_nbns_name(&pd[offset], pd, offset, name);
984
985                         add_item_to_tree(nbdgm_tree, offset, len, "Destination name: %s",
986                                         name);
987                 }
988         }
989 }