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