1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright (c) 1999 by Sun Microsystems, Inc.
24*0Sstevel@tonic-gate  * All rights reserved.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * References used throughout this code:
31*0Sstevel@tonic-gate  *
32*0Sstevel@tonic-gate  * [RFC1001] :	PROTOCOL STANDARD FOR A NetBIOS SERVICE
33*0Sstevel@tonic-gate  *			ON A TCP/UDP TRANSPORT:
34*0Sstevel@tonic-gate  *			CONCEPTS AND METHODS
35*0Sstevel@tonic-gate  *		NetBIOS Working Group, March 1987
36*0Sstevel@tonic-gate  *
37*0Sstevel@tonic-gate  * [RFC1002] :	PROTOCOL STANDARD FOR A NetBIOS SERVICE
38*0Sstevel@tonic-gate  *			ON A TCP/UDP TRANSPORT:
39*0Sstevel@tonic-gate  *			DETAILED SPECIFICATIONS
40*0Sstevel@tonic-gate  *		NetBIOS Working Group, March 1987
41*0Sstevel@tonic-gate  */
42*0Sstevel@tonic-gate 
43*0Sstevel@tonic-gate #include <fcntl.h>
44*0Sstevel@tonic-gate #include "snoop.h"
45*0Sstevel@tonic-gate #include <stdio.h>
46*0Sstevel@tonic-gate #include <ctype.h>
47*0Sstevel@tonic-gate #include "snoop.h"
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate extern char *dlc_header;
50*0Sstevel@tonic-gate char *show_type();
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate /* See snoop_smb.c */
53*0Sstevel@tonic-gate extern void interpret_smb(int flags, uchar_t *data, int len);
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate /*
56*0Sstevel@tonic-gate  * NBT Session Packet Header
57*0Sstevel@tonic-gate  * [RFC 1002, Sec. 4.3.1]
58*0Sstevel@tonic-gate  */
59*0Sstevel@tonic-gate struct nbt_ss {
60*0Sstevel@tonic-gate 	uchar_t type;
61*0Sstevel@tonic-gate 	uchar_t flags;
62*0Sstevel@tonic-gate 	ushort_t length;
63*0Sstevel@tonic-gate };
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate /*
66*0Sstevel@tonic-gate  * NBT Session Request Packet trailer
67*0Sstevel@tonic-gate  * [RFC 1002, Sec. 4.3.2]
68*0Sstevel@tonic-gate  */
69*0Sstevel@tonic-gate struct callnames {
70*0Sstevel@tonic-gate 	uchar_t space;		/* padding */
71*0Sstevel@tonic-gate 	uchar_t calledname[32];
72*0Sstevel@tonic-gate 	uchar_t nullchar;		/* padding */
73*0Sstevel@tonic-gate 	uchar_t space2;		/* padding */
74*0Sstevel@tonic-gate 	uchar_t callingname[32];
75*0Sstevel@tonic-gate 	uchar_t nullchar2;	/* padding */
76*0Sstevel@tonic-gate };
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate static void interpret_netbios_names(int flags, uchar_t *data, int len,
80*0Sstevel@tonic-gate 					char *xtra);
81*0Sstevel@tonic-gate static void netbiosname2ascii(char *asciiname, uchar_t *netbiosname);
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate /*
84*0Sstevel@tonic-gate  * Helpers to read network-order values,
85*0Sstevel@tonic-gate  * with NO alignment assumed.
86*0Sstevel@tonic-gate  */
87*0Sstevel@tonic-gate static ushort_t
88*0Sstevel@tonic-gate getshort(uchar_t *p) {
89*0Sstevel@tonic-gate 	return (p[1] + (p[0]<<8));
90*0Sstevel@tonic-gate }
91*0Sstevel@tonic-gate static uint_t
92*0Sstevel@tonic-gate getlong(uchar_t *p)
93*0Sstevel@tonic-gate {
94*0Sstevel@tonic-gate 	return (p[3] + (p[2]<<8) + (p[1]<<16) + (p[0]<<24));
95*0Sstevel@tonic-gate }
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate /*
98*0Sstevel@tonic-gate  * NM_FLAGS fields in the NetBIOS Name Service Packet header.
99*0Sstevel@tonic-gate  * [RFC 1002,  Sec. 4.2.1.1]
100*0Sstevel@tonic-gate  */
101*0Sstevel@tonic-gate static void
102*0Sstevel@tonic-gate print_flag_details(int headerflags)
103*0Sstevel@tonic-gate {
104*0Sstevel@tonic-gate 	if (headerflags & 1<<4)
105*0Sstevel@tonic-gate 		sprintf(get_line(0, 0), "   - Broadcast");
106*0Sstevel@tonic-gate 	if (headerflags & 1<<7)
107*0Sstevel@tonic-gate 		sprintf(get_line(0, 0), "   - Recursion Available");
108*0Sstevel@tonic-gate 	if (headerflags & 1<<8)
109*0Sstevel@tonic-gate 		sprintf(get_line(0, 0), "   - Recursion Desired");
110*0Sstevel@tonic-gate 	if (headerflags & 1<<9)
111*0Sstevel@tonic-gate 		sprintf(get_line(0, 0), "   - Truncation Flag");
112*0Sstevel@tonic-gate 	if (headerflags & 1<<10)
113*0Sstevel@tonic-gate 		sprintf(get_line(0, 0), "   - Authoritative Answer");
114*0Sstevel@tonic-gate }
115*0Sstevel@tonic-gate 
116*0Sstevel@tonic-gate /*
117*0Sstevel@tonic-gate  * Possible errors in NetBIOS name service packets.
118*0Sstevel@tonic-gate  * [RFC 1002,  Sec. 4.2.6, 4.2.11, 4.2.14]
119*0Sstevel@tonic-gate  */
120*0Sstevel@tonic-gate static void
121*0Sstevel@tonic-gate getrcodeerr(int headerflags, char *errortype)
122*0Sstevel@tonic-gate {
123*0Sstevel@tonic-gate 	int error = (headerflags & 0xf);
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate 	switch (error) {
126*0Sstevel@tonic-gate 	case 0:
127*0Sstevel@tonic-gate 		sprintf(errortype, "Success");
128*0Sstevel@tonic-gate 		break;
129*0Sstevel@tonic-gate 	case 1:
130*0Sstevel@tonic-gate 		sprintf(errortype, "Format Error");
131*0Sstevel@tonic-gate 		break;
132*0Sstevel@tonic-gate 	case 2:
133*0Sstevel@tonic-gate 		sprintf(errortype, "Server Failure");
134*0Sstevel@tonic-gate 		break;
135*0Sstevel@tonic-gate 	case 3:
136*0Sstevel@tonic-gate 		sprintf(errortype, "Name Error");
137*0Sstevel@tonic-gate 		break;
138*0Sstevel@tonic-gate 	case 4:
139*0Sstevel@tonic-gate 		sprintf(errortype, "Unsupported Request Error");
140*0Sstevel@tonic-gate 		break;
141*0Sstevel@tonic-gate 	case 5:
142*0Sstevel@tonic-gate 		sprintf(errortype, "Refused Error");
143*0Sstevel@tonic-gate 		break;
144*0Sstevel@tonic-gate 	case 6:
145*0Sstevel@tonic-gate 		sprintf(errortype, "Active Error");
146*0Sstevel@tonic-gate 		break;
147*0Sstevel@tonic-gate 	case 7:
148*0Sstevel@tonic-gate 		sprintf(errortype, "Name in Conflict Error");
149*0Sstevel@tonic-gate 		break;
150*0Sstevel@tonic-gate 	default:
151*0Sstevel@tonic-gate 		sprintf(errortype, "Unknown Error");
152*0Sstevel@tonic-gate 		break;
153*0Sstevel@tonic-gate 	}
154*0Sstevel@tonic-gate }
155*0Sstevel@tonic-gate 
156*0Sstevel@tonic-gate /*
157*0Sstevel@tonic-gate  * OPCODE fields in the NetBIOS Name Service Packet header.
158*0Sstevel@tonic-gate  * [RFC 1002, Sec. 4.2.1.1]
159*0Sstevel@tonic-gate  */
160*0Sstevel@tonic-gate static void
161*0Sstevel@tonic-gate print_ns_type(int flags, int headerflags, char *xtra)
162*0Sstevel@tonic-gate {
163*0Sstevel@tonic-gate 	int opcode = (headerflags & 0x7800)>>11;
164*0Sstevel@tonic-gate 	int response = (headerflags & 1<<15);
165*0Sstevel@tonic-gate 	char *resptype = response ? "Response" : "Request";
166*0Sstevel@tonic-gate 	char *optype;
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate 	switch (opcode) {
169*0Sstevel@tonic-gate 	case 0:
170*0Sstevel@tonic-gate 		optype = "Query";
171*0Sstevel@tonic-gate 		break;
172*0Sstevel@tonic-gate 	case 5:
173*0Sstevel@tonic-gate 		optype = "Registration";
174*0Sstevel@tonic-gate 		break;
175*0Sstevel@tonic-gate 	case 6:
176*0Sstevel@tonic-gate 		optype = "Release";
177*0Sstevel@tonic-gate 		break;
178*0Sstevel@tonic-gate 	case 7:
179*0Sstevel@tonic-gate 		optype = "WACK";
180*0Sstevel@tonic-gate 		break;
181*0Sstevel@tonic-gate 	case 8:
182*0Sstevel@tonic-gate 		optype = "Refresh";
183*0Sstevel@tonic-gate 		break;
184*0Sstevel@tonic-gate 	default:
185*0Sstevel@tonic-gate 		optype = "Unknown";
186*0Sstevel@tonic-gate 		break;
187*0Sstevel@tonic-gate 	}
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate 	if (flags & F_DTAIL)
190*0Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Type = %s %s", optype, resptype);
191*0Sstevel@tonic-gate 	else
192*0Sstevel@tonic-gate 		sprintf(xtra, "%s %s", optype, resptype);
193*0Sstevel@tonic-gate }
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate 
196*0Sstevel@tonic-gate /*
197*0Sstevel@tonic-gate  * Interpret Datagram Packets
198*0Sstevel@tonic-gate  * [RFC 1002, Sec. 4.4]
199*0Sstevel@tonic-gate  */
200*0Sstevel@tonic-gate void
201*0Sstevel@tonic-gate interpret_netbios_datagram(int flags, uchar_t *data, int len)
202*0Sstevel@tonic-gate {
203*0Sstevel@tonic-gate 	char name[24];
204*0Sstevel@tonic-gate 	int packettype = data[0];
205*0Sstevel@tonic-gate 	int packetlen;
206*0Sstevel@tonic-gate 	data++;
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate 	if (packettype < 0x10 || packettype > 0x11)
209*0Sstevel@tonic-gate 		return;
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate 	if (flags & F_SUM) {
212*0Sstevel@tonic-gate 		data += 14;
213*0Sstevel@tonic-gate 		netbiosname2ascii(name, data);
214*0Sstevel@tonic-gate 		sprintf(get_sum_line(),
215*0Sstevel@tonic-gate 				"NBT Datagram Service Type=%d Source=%s",
216*0Sstevel@tonic-gate 				packettype, name);
217*0Sstevel@tonic-gate 	}
218*0Sstevel@tonic-gate 
219*0Sstevel@tonic-gate 	if (flags & F_DTAIL) {
220*0Sstevel@tonic-gate 		show_header("NBT:  ", "Netbios Datagram Service Header", len);
221*0Sstevel@tonic-gate 		show_space();
222*0Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Datagram Packet Type = 0x%.2x",
223*0Sstevel@tonic-gate 					packettype);
224*0Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Datagram Flags = 0x%.2x",
225*0Sstevel@tonic-gate 					data[0]);
226*0Sstevel@tonic-gate 		data++;
227*0Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Datagram ID = 0x%.4x",
228*0Sstevel@tonic-gate 					getshort(data));
229*0Sstevel@tonic-gate 		data += 2;
230*0Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Source IP = %d.%d.%d.%d",
231*0Sstevel@tonic-gate 					data[0], data[1], data[2], data[3]);
232*0Sstevel@tonic-gate 		data += 4;
233*0Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Source Port = %d",
234*0Sstevel@tonic-gate 					getshort(data));
235*0Sstevel@tonic-gate 		data += 2;
236*0Sstevel@tonic-gate 		packetlen = getshort(data);
237*0Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Datagram Length = 0x%.4x",
238*0Sstevel@tonic-gate 					packetlen);
239*0Sstevel@tonic-gate 		data += 2;
240*0Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Packet Offset = 0x%.4x",
241*0Sstevel@tonic-gate 					getshort(data));
242*0Sstevel@tonic-gate 		data += 3;
243*0Sstevel@tonic-gate 		netbiosname2ascii(name, data);
244*0Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Source Name = %s", name);
245*0Sstevel@tonic-gate 		data += 34;
246*0Sstevel@tonic-gate 		netbiosname2ascii(name, data);
247*0Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Destination Name = %s", name);
248*0Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Number of data bytes remaining = %d",
249*0Sstevel@tonic-gate 					packetlen - 68);
250*0Sstevel@tonic-gate 		show_trailer();
251*0Sstevel@tonic-gate 	}
252*0Sstevel@tonic-gate }
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate /*
255*0Sstevel@tonic-gate  * Interpret NetBIOS Name Service packets.
256*0Sstevel@tonic-gate  * [RFC 1002, Sec. 4.2]
257*0Sstevel@tonic-gate  */
258*0Sstevel@tonic-gate void
259*0Sstevel@tonic-gate interpret_netbios_ns(int flags, uchar_t *data, int len)
260*0Sstevel@tonic-gate {
261*0Sstevel@tonic-gate 	int headerflags, qcount, acount, nscount, arcount;
262*0Sstevel@tonic-gate 	int transid;
263*0Sstevel@tonic-gate 	char name[24];
264*0Sstevel@tonic-gate 	char extra[256];
265*0Sstevel@tonic-gate 	char errortype[50];
266*0Sstevel@tonic-gate 	int rdatalen;
267*0Sstevel@tonic-gate 	int rrflags;
268*0Sstevel@tonic-gate 	int nameptr;
269*0Sstevel@tonic-gate 	int nodecode;
270*0Sstevel@tonic-gate 	char *nodetype;
271*0Sstevel@tonic-gate 	uchar_t *data0 = data;
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate 	transid = getshort(data); data += 2;
274*0Sstevel@tonic-gate 	headerflags = getshort(data); data += 2;
275*0Sstevel@tonic-gate 	qcount = getshort(data); data += 2;
276*0Sstevel@tonic-gate 	acount = getshort(data); data += 2;
277*0Sstevel@tonic-gate 	nscount = getshort(data); data += 2;
278*0Sstevel@tonic-gate 	arcount = getshort(data); data += 2;
279*0Sstevel@tonic-gate 	getrcodeerr(headerflags, errortype);
280*0Sstevel@tonic-gate 
281*0Sstevel@tonic-gate 	if (flags & F_SUM) {
282*0Sstevel@tonic-gate 		print_ns_type(flags, headerflags, extra);
283*0Sstevel@tonic-gate 		data++;
284*0Sstevel@tonic-gate 		netbiosname2ascii(name, data);
285*0Sstevel@tonic-gate 		sprintf(get_sum_line(), "NBT NS %s for %s, %s",
286*0Sstevel@tonic-gate 			extra, name, errortype);
287*0Sstevel@tonic-gate 
288*0Sstevel@tonic-gate 	}
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 	if (flags & F_DTAIL) {
292*0Sstevel@tonic-gate 		show_header("NBT:  ", "Netbios Name Service Header", len);
293*0Sstevel@tonic-gate 		show_space();
294*0Sstevel@tonic-gate 		print_ns_type(flags, headerflags, 0);
295*0Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Status = %s", errortype);
296*0Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Transaction ID = 0x%.4x", transid);
297*0Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Flags Summary = 0x%.4x",
298*0Sstevel@tonic-gate 					headerflags);
299*0Sstevel@tonic-gate 		print_flag_details(headerflags);
300*0Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Question count = %d", qcount);
301*0Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Answer Count = %d", acount);
302*0Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Name Service Count = %d", nscount);
303*0Sstevel@tonic-gate 		sprintf(get_line(0, 0),
304*0Sstevel@tonic-gate 				"Additional Record Count = %d", arcount);
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate 		/*
307*0Sstevel@tonic-gate 		 * Question Section Packet Description from
308*0Sstevel@tonic-gate 		 * [RFC 1002, Sec. 4.2.1.2]
309*0Sstevel@tonic-gate 		 */
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate 		if (qcount) {
312*0Sstevel@tonic-gate 			data++;
313*0Sstevel@tonic-gate 			netbiosname2ascii(name, data);
314*0Sstevel@tonic-gate 			sprintf(get_line(0, 0), "Question Name = %s", name);
315*0Sstevel@tonic-gate 			data += 33;
316*0Sstevel@tonic-gate 			sprintf(get_line(0, 0), "Question Type = 0x%.4x",
317*0Sstevel@tonic-gate 						getshort(data));
318*0Sstevel@tonic-gate 			data += 2;
319*0Sstevel@tonic-gate 			sprintf(get_line(0, 0), "Question Class = 0x%.4x",
320*0Sstevel@tonic-gate 						getshort(data));
321*0Sstevel@tonic-gate 			data += 2;
322*0Sstevel@tonic-gate 		}
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate 		/*
325*0Sstevel@tonic-gate 		 * Resrouce Record Packet Description from
326*0Sstevel@tonic-gate 		 * [RFC 1002, Sec. 4.2.1.3]
327*0Sstevel@tonic-gate 		 */
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 		if ((acount || nscount || arcount) ||
330*0Sstevel@tonic-gate 		    (qcount+acount+nscount+arcount == 0)) {
331*0Sstevel@tonic-gate 			/* Second level encoding from RFC883 (p.31, 32) */
332*0Sstevel@tonic-gate 			if (data[0] & 0xc0) {
333*0Sstevel@tonic-gate 				nameptr = getshort(data)&0x3fff;
334*0Sstevel@tonic-gate 				netbiosname2ascii(name, (data0+nameptr+1));
335*0Sstevel@tonic-gate 				sprintf(get_line(0, 0),
336*0Sstevel@tonic-gate 					"Resource Record Name = %s", name);
337*0Sstevel@tonic-gate 				data += 2;
338*0Sstevel@tonic-gate 			} else {
339*0Sstevel@tonic-gate 				data++;
340*0Sstevel@tonic-gate 				netbiosname2ascii(name, data);
341*0Sstevel@tonic-gate 				sprintf(get_line(0, 0),
342*0Sstevel@tonic-gate 					"Resource Record Name = %s", name);
343*0Sstevel@tonic-gate 				data += 33;
344*0Sstevel@tonic-gate 			}
345*0Sstevel@tonic-gate 			sprintf(get_line(0, 0),
346*0Sstevel@tonic-gate 					"Resource Record Type = 0x%.4x",
347*0Sstevel@tonic-gate 					getshort(data));
348*0Sstevel@tonic-gate 			data += 2;
349*0Sstevel@tonic-gate 			sprintf(get_line(0, 0),
350*0Sstevel@tonic-gate 					"Resource Record Class = 0x%.4x",
351*0Sstevel@tonic-gate 					getshort(data));
352*0Sstevel@tonic-gate 			data += 2;
353*0Sstevel@tonic-gate 			sprintf(get_line(0, 0),
354*0Sstevel@tonic-gate 				"Time to Live (Milliseconds) = %d",
355*0Sstevel@tonic-gate 				getlong(data));
356*0Sstevel@tonic-gate 			data += 4;
357*0Sstevel@tonic-gate 			rdatalen = getshort(data);
358*0Sstevel@tonic-gate 			sprintf(get_line(0, 0), "RDATA Length = 0x%.4x",
359*0Sstevel@tonic-gate 						rdatalen);
360*0Sstevel@tonic-gate 			data += 2;
361*0Sstevel@tonic-gate 			/* 15.4.2.1.3 */
362*0Sstevel@tonic-gate 			if (rdatalen == 6) {
363*0Sstevel@tonic-gate 				rrflags = getshort(data);
364*0Sstevel@tonic-gate 				data += 2;
365*0Sstevel@tonic-gate 				sprintf(get_line(0, 0),
366*0Sstevel@tonic-gate 					"Resource Record Flags = 0x%.4x",
367*0Sstevel@tonic-gate 					rrflags);
368*0Sstevel@tonic-gate 				nodecode = (rrflags>>13)& 0x11;
369*0Sstevel@tonic-gate 				if (nodecode == 0) nodetype = "B";
370*0Sstevel@tonic-gate 				if (nodecode == 1) nodetype = "P";
371*0Sstevel@tonic-gate 				if (nodecode == 2) nodetype = "M";
372*0Sstevel@tonic-gate 				sprintf(get_line(0, 0), "   - %s, %s node",
373*0Sstevel@tonic-gate 					(rrflags & 1<<15) ?
374*0Sstevel@tonic-gate 					"Group NetBIOS Name":
375*0Sstevel@tonic-gate 					"Unique NetBIOS Name", nodetype);
376*0Sstevel@tonic-gate 				sprintf(get_line(0, 0),
377*0Sstevel@tonic-gate 					"Owner IP Address = %d.%d.%d.%d",
378*0Sstevel@tonic-gate 					data[0], data[1], data[2], data[3]);
379*0Sstevel@tonic-gate 			}
380*0Sstevel@tonic-gate 		}
381*0Sstevel@tonic-gate 		show_trailer();
382*0Sstevel@tonic-gate 
383*0Sstevel@tonic-gate 	}
384*0Sstevel@tonic-gate }
385*0Sstevel@tonic-gate 
386*0Sstevel@tonic-gate /*
387*0Sstevel@tonic-gate  * Interpret NetBIOS session packets.
388*0Sstevel@tonic-gate  * [RFC 1002, Sec. 4.3]
389*0Sstevel@tonic-gate  */
390*0Sstevel@tonic-gate void
391*0Sstevel@tonic-gate interpret_netbios_ses(int flags, uchar_t *data, int len)
392*0Sstevel@tonic-gate {
393*0Sstevel@tonic-gate 	struct nbt_ss *ss;
394*0Sstevel@tonic-gate 	uchar_t *trailer;
395*0Sstevel@tonic-gate 	int length = len - 4;   /* NBT packet length without header */
396*0Sstevel@tonic-gate 	char *type;
397*0Sstevel@tonic-gate 	char extrainfo[300];
398*0Sstevel@tonic-gate 
399*0Sstevel@tonic-gate 	if (len < sizeof (struct nbt_ss))
400*0Sstevel@tonic-gate 		return;
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate 	/*
403*0Sstevel@tonic-gate 	 * Packets that are fragments of a large NetBIOS session
404*0Sstevel@tonic-gate 	 * message will have no NetBIOS header.  (Only the first
405*0Sstevel@tonic-gate 	 * TCP segment will have a NetBIOS header.)  It turns out
406*0Sstevel@tonic-gate 	 * that very often, such fragments start with SMB data, so
407*0Sstevel@tonic-gate 	 * we should try to recognize and decode them.
408*0Sstevel@tonic-gate 	 */
409*0Sstevel@tonic-gate 	if (data[0] == 0xff &&
410*0Sstevel@tonic-gate 	    data[1] == 'S' &&
411*0Sstevel@tonic-gate 	    data[2] == 'M' &&
412*0Sstevel@tonic-gate 	    data[3] == 'B') {
413*0Sstevel@tonic-gate 		interpret_smb(flags, data, len);
414*0Sstevel@tonic-gate 		return;
415*0Sstevel@tonic-gate 	}
416*0Sstevel@tonic-gate 
417*0Sstevel@tonic-gate 	/* LINTED PTRALIGN */
418*0Sstevel@tonic-gate 	ss = (struct nbt_ss *)data;
419*0Sstevel@tonic-gate 	trailer = data + sizeof (*ss);
420*0Sstevel@tonic-gate 	extrainfo[0] = '\0';
421*0Sstevel@tonic-gate 
422*0Sstevel@tonic-gate 	if (flags & F_SUM) {
423*0Sstevel@tonic-gate 		switch (ss->type) {
424*0Sstevel@tonic-gate 		case 0x00:
425*0Sstevel@tonic-gate 			type = "SESSION MESSAGE";
426*0Sstevel@tonic-gate 			break;
427*0Sstevel@tonic-gate 		case 0x81:
428*0Sstevel@tonic-gate 			type = "SESSION REQUEST";
429*0Sstevel@tonic-gate 			interpret_netbios_names(flags, trailer,
430*0Sstevel@tonic-gate 						length, extrainfo);
431*0Sstevel@tonic-gate 			break;
432*0Sstevel@tonic-gate 		case 0x82:
433*0Sstevel@tonic-gate 			type = "POSITIVE SESSION RESPONSE";
434*0Sstevel@tonic-gate 			break;
435*0Sstevel@tonic-gate 		case 0x83:
436*0Sstevel@tonic-gate 			type = "NEGATIVE SESSION RESPONSE";
437*0Sstevel@tonic-gate 			break;
438*0Sstevel@tonic-gate 		case 0x84:
439*0Sstevel@tonic-gate 			type = "RETARGET SESSION RESPONSE";
440*0Sstevel@tonic-gate 			break;
441*0Sstevel@tonic-gate 		case 0x85:
442*0Sstevel@tonic-gate 			type = "SESSION KEEP ALIVE";
443*0Sstevel@tonic-gate 			break;
444*0Sstevel@tonic-gate 		default:
445*0Sstevel@tonic-gate 			type = "Unknown";
446*0Sstevel@tonic-gate 			break;
447*0Sstevel@tonic-gate 		}
448*0Sstevel@tonic-gate 		(void) sprintf(get_sum_line(),
449*0Sstevel@tonic-gate 			"NBT Type=%s %sLength=%d", type, extrainfo, length);
450*0Sstevel@tonic-gate 	}
451*0Sstevel@tonic-gate 
452*0Sstevel@tonic-gate 	if (flags & F_DTAIL) {
453*0Sstevel@tonic-gate 		show_header("NBT:  ", "NBT Header", len);
454*0Sstevel@tonic-gate 		show_space();
455*0Sstevel@tonic-gate 
456*0Sstevel@tonic-gate 		switch (ss->type) {
457*0Sstevel@tonic-gate 		case 0x00:
458*0Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0),
459*0Sstevel@tonic-gate 			"Type = SESSION MESSAGE");
460*0Sstevel@tonic-gate 			break;
461*0Sstevel@tonic-gate 		case 0x81:
462*0Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0),
463*0Sstevel@tonic-gate 			"Type = SESSION REQUEST");
464*0Sstevel@tonic-gate 			interpret_netbios_names(flags, trailer, length, 0);
465*0Sstevel@tonic-gate 			break;
466*0Sstevel@tonic-gate 		case 0x82:
467*0Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0),
468*0Sstevel@tonic-gate 			"Type = POSITIVE SESSION RESPONSE");
469*0Sstevel@tonic-gate 			break;
470*0Sstevel@tonic-gate 		case 0x83:
471*0Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0),
472*0Sstevel@tonic-gate 			"Type = NEGATIVE SESSION RESPONSE");
473*0Sstevel@tonic-gate 			break;
474*0Sstevel@tonic-gate 		case 0x84:
475*0Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0),
476*0Sstevel@tonic-gate 			"Type = RETARGET SESSION RESPONSE");
477*0Sstevel@tonic-gate 			break;
478*0Sstevel@tonic-gate 		case 0x85:
479*0Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0),
480*0Sstevel@tonic-gate 			"Type = SESSION KEEP ALIVE");
481*0Sstevel@tonic-gate 			break;
482*0Sstevel@tonic-gate 		default:
483*0Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0),
484*0Sstevel@tonic-gate 			"Type = Unknown");
485*0Sstevel@tonic-gate 			break;
486*0Sstevel@tonic-gate 		}
487*0Sstevel@tonic-gate 
488*0Sstevel@tonic-gate 		(void) sprintf(get_line(0, 0), "Length = %d bytes", length);
489*0Sstevel@tonic-gate 		show_trailer();
490*0Sstevel@tonic-gate 	}
491*0Sstevel@tonic-gate 
492*0Sstevel@tonic-gate 	/*
493*0Sstevel@tonic-gate 	 * SMB packets have { 0xff, 'S', 'M', 'B' }
494*0Sstevel@tonic-gate 	 * in the first four bytes.  If we find that,
495*0Sstevel@tonic-gate 	 * let snoop_smb.c have a look at it.
496*0Sstevel@tonic-gate 	 */
497*0Sstevel@tonic-gate 	if (ss->type == 0x00 &&
498*0Sstevel@tonic-gate 	    length > 0 &&
499*0Sstevel@tonic-gate 	    trailer[0] == 0xff &&
500*0Sstevel@tonic-gate 	    trailer[1] == 'S' &&
501*0Sstevel@tonic-gate 	    trailer[2] == 'M' &&
502*0Sstevel@tonic-gate 	    trailer[3] == 'B')
503*0Sstevel@tonic-gate 		interpret_smb(flags, trailer, len);
504*0Sstevel@tonic-gate }
505*0Sstevel@tonic-gate 
506*0Sstevel@tonic-gate /*
507*0Sstevel@tonic-gate  * NetBIOS name encoding (First Level Encoding)
508*0Sstevel@tonic-gate  * [RFC 1001, Sec. 4.1]
509*0Sstevel@tonic-gate  */
510*0Sstevel@tonic-gate static void
511*0Sstevel@tonic-gate netbiosname2ascii(char *aname, uchar_t *nbname)
512*0Sstevel@tonic-gate {
513*0Sstevel@tonic-gate 	int c, i, j;
514*0Sstevel@tonic-gate 
515*0Sstevel@tonic-gate 	i = j = 0;
516*0Sstevel@tonic-gate 	for (;;) {
517*0Sstevel@tonic-gate 		c = nbname[i++] - 'A';
518*0Sstevel@tonic-gate 		c = (c << 4) +
519*0Sstevel@tonic-gate 			nbname[i++] - 'A';
520*0Sstevel@tonic-gate 		/* 16th char is the "type" */
521*0Sstevel@tonic-gate 		if (i >= 32)
522*0Sstevel@tonic-gate 			break;
523*0Sstevel@tonic-gate 		if (iscntrl(c))
524*0Sstevel@tonic-gate 			c = '.';
525*0Sstevel@tonic-gate 		if (c != ' ')
526*0Sstevel@tonic-gate 			aname[j++] = c;
527*0Sstevel@tonic-gate 	}
528*0Sstevel@tonic-gate 	sprintf(&aname[j], "[%x]", c);
529*0Sstevel@tonic-gate }
530*0Sstevel@tonic-gate 
531*0Sstevel@tonic-gate /*
532*0Sstevel@tonic-gate  * Interpret the names in a Session Request packet.
533*0Sstevel@tonic-gate  * [RFC 1002, Sec. 4.3.2]
534*0Sstevel@tonic-gate  */
535*0Sstevel@tonic-gate static void
536*0Sstevel@tonic-gate interpret_netbios_names(int flags, uchar_t *data, int len, char *xtra)
537*0Sstevel@tonic-gate {
538*0Sstevel@tonic-gate 	char  calledname[24];
539*0Sstevel@tonic-gate 	char callingname[24];
540*0Sstevel@tonic-gate 	struct callnames *names = (struct callnames *)data;
541*0Sstevel@tonic-gate 
542*0Sstevel@tonic-gate 	if (len < sizeof (*names))
543*0Sstevel@tonic-gate 		return;
544*0Sstevel@tonic-gate 
545*0Sstevel@tonic-gate 	netbiosname2ascii(calledname, names->calledname);
546*0Sstevel@tonic-gate 	netbiosname2ascii(callingname, names->callingname);
547*0Sstevel@tonic-gate 
548*0Sstevel@tonic-gate 	if (flags & F_SUM) {
549*0Sstevel@tonic-gate 		sprintf(xtra, "Dest=%s Source=%s ", calledname, callingname);
550*0Sstevel@tonic-gate 	}
551*0Sstevel@tonic-gate 
552*0Sstevel@tonic-gate 	if (flags & F_DTAIL) {
553*0Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Destination = %s", calledname);
554*0Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Source = %s", callingname);
555*0Sstevel@tonic-gate 	}
556*0Sstevel@tonic-gate }
557